diff options
Diffstat (limited to 'unotools/source')
47 files changed, 17674 insertions, 0 deletions
diff --git a/unotools/source/accessibility/accessiblerelationsethelper.cxx b/unotools/source/accessibility/accessiblerelationsethelper.cxx new file mode 100644 index 000000000000..419a072678df --- /dev/null +++ b/unotools/source/accessibility/accessiblerelationsethelper.cxx @@ -0,0 +1,275 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: accessiblerelationsethelper.cxx,v $ + * $Revision: 1.10 $ + * + * 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_unotools.hxx" + + +#include "unotools/accessiblerelationsethelper.hxx" +#include <rtl/uuid.h> +#include <vector> +#include <comphelper/sequence.hxx> + +using namespace ::utl; +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +class AccessibleRelationSetHelperImpl +{ +public: + AccessibleRelationSetHelperImpl(); + AccessibleRelationSetHelperImpl(const AccessibleRelationSetHelperImpl& rImpl); + ~AccessibleRelationSetHelperImpl(); + + sal_Int32 getRelationCount( ) + throw (uno::RuntimeException); + AccessibleRelation getRelation( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, + uno::RuntimeException); + sal_Bool containsRelation( sal_Int16 aRelationType ) + throw (uno::RuntimeException); + AccessibleRelation getRelationByType( sal_Int16 aRelationType ) + throw (uno::RuntimeException); + void AddRelation(const AccessibleRelation& rRelation) + throw (uno::RuntimeException); + +private: + std::vector<AccessibleRelation> maRelations; +}; + +AccessibleRelationSetHelperImpl::AccessibleRelationSetHelperImpl() +{ +} + +AccessibleRelationSetHelperImpl::AccessibleRelationSetHelperImpl(const AccessibleRelationSetHelperImpl& rImpl) + : maRelations(rImpl.maRelations) +{ +} + +AccessibleRelationSetHelperImpl::~AccessibleRelationSetHelperImpl() +{ +} + +sal_Int32 AccessibleRelationSetHelperImpl::getRelationCount( ) + throw (uno::RuntimeException) +{ + return maRelations.size(); +} + +AccessibleRelation AccessibleRelationSetHelperImpl::getRelation( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + if ((nIndex < 0) || (static_cast<sal_uInt32>(nIndex) >= maRelations.size())) + throw lang::IndexOutOfBoundsException(); + return maRelations[nIndex]; +} + +sal_Bool AccessibleRelationSetHelperImpl::containsRelation( sal_Int16 aRelationType ) + throw (uno::RuntimeException) +{ + AccessibleRelation defaultRelation; // default is INVALID + AccessibleRelation relationByType = getRelationByType(aRelationType); + return relationByType.RelationType != defaultRelation.RelationType; +} + +AccessibleRelation AccessibleRelationSetHelperImpl::getRelationByType( sal_Int16 aRelationType ) + throw (uno::RuntimeException) +{ + sal_Int32 nCount(getRelationCount()); + sal_Int32 i(0); + sal_Bool bFound(sal_False); + while ((i < nCount) && !bFound) + { + if (maRelations[i].RelationType == aRelationType) + return maRelations[i]; + else + i++; + } + return AccessibleRelation(); +} + +void AccessibleRelationSetHelperImpl::AddRelation(const AccessibleRelation& rRelation) + throw (uno::RuntimeException) +{ + sal_Int32 nCount(getRelationCount()); + sal_Int32 i(0); + sal_Bool bFound(sal_False); + while ((i < nCount) && !bFound) + { + if (maRelations[i].RelationType == rRelation.RelationType) + bFound = sal_True; + else + i++; + } + if (bFound) + maRelations[i].TargetSet = comphelper::concatSequences(maRelations[i].TargetSet, rRelation.TargetSet); + else + maRelations.push_back(rRelation); +} + +//===== internal ============================================================ + +AccessibleRelationSetHelper::AccessibleRelationSetHelper () + : mpHelperImpl(NULL) +{ + mpHelperImpl = new AccessibleRelationSetHelperImpl(); +} + +AccessibleRelationSetHelper::AccessibleRelationSetHelper (const AccessibleRelationSetHelper& rHelper) + : cppu::WeakImplHelper1<XAccessibleRelationSet>() + , mpHelperImpl(NULL) +{ + if (rHelper.mpHelperImpl) + mpHelperImpl = new AccessibleRelationSetHelperImpl(*rHelper.mpHelperImpl); + else + mpHelperImpl = new AccessibleRelationSetHelperImpl(); +} + +AccessibleRelationSetHelper::~AccessibleRelationSetHelper(void) +{ + delete mpHelperImpl; +} + +//===== XAccessibleRelationSet ============================================== + + /** Returns the number of relations in this relation set. + + @return + Returns the number of relations or zero if there are none. + */ +sal_Int32 SAL_CALL + AccessibleRelationSetHelper::getRelationCount( ) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->getRelationCount(); +} + + /** Returns the relation of this relation set that is specified by + the given index. + + @param nIndex + This index specifies the relatio to return. + + @return + For a valid index, i.e. inside the range 0 to the number of + relations minus one, the returned value is the requested + relation. If the index is invalid then the returned relation + has the type INVALID. + + */ + AccessibleRelation SAL_CALL + AccessibleRelationSetHelper::getRelation( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, + uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->getRelation(nIndex); +} + + /** Tests whether the relation set contains a relation matching the + specified key. + + @param aRelationType + The type of relation to look for in this set of relations. This + has to be one of the constants of + <type>AccessibleRelationType</type>. + + @return + Returns <TRUE/> if there is a (at least one) relation of the + given type and <FALSE/> if there is no such relation in the set. + */ +sal_Bool SAL_CALL + AccessibleRelationSetHelper::containsRelation( sal_Int16 aRelationType ) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->containsRelation(aRelationType); +} + + /** Retrieve and return the relation with the given relation type. + + @param aRelationType + The type of the relation to return. This has to be one of the + constants of <type>AccessibleRelationType</type>. + + @return + If a relation with the given type could be found than (a copy + of) this relation is returned. Otherwise a relation with the + type INVALID is returned. + */ +AccessibleRelation SAL_CALL + AccessibleRelationSetHelper::getRelationByType( sal_Int16 aRelationType ) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->getRelationByType(aRelationType); +} + +void AccessibleRelationSetHelper::AddRelation(const AccessibleRelation& rRelation) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + mpHelperImpl->AddRelation(rRelation); +} + +//===== XTypeProvider ======================================================= + +uno::Sequence< ::com::sun::star::uno::Type> + AccessibleRelationSetHelper::getTypes (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + const ::com::sun::star::uno::Type aTypeList[] = { + ::getCppuType((const uno::Reference< + XAccessibleRelationSet>*)0), + ::getCppuType((const uno::Reference< + lang::XTypeProvider>*)0) + }; + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> + aTypeSequence (aTypeList, 2); + return aTypeSequence; +} + +uno::Sequence<sal_Int8> SAL_CALL + AccessibleRelationSetHelper::getImplementationId (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid ((sal_uInt8 *)aId.getArray(), 0, sal_True); + } + return aId; +} diff --git a/unotools/source/accessibility/accessiblestatesethelper.cxx b/unotools/source/accessibility/accessiblestatesethelper.cxx new file mode 100644 index 000000000000..71882d66278b --- /dev/null +++ b/unotools/source/accessibility/accessiblestatesethelper.cxx @@ -0,0 +1,349 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: accessiblestatesethelper.cxx,v $ + * $Revision: 1.15 $ + * + * 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_unotools.hxx" + + +#include "unotools/accessiblestatesethelper.hxx" +#include <rtl/uuid.h> +#include <tools/debug.hxx> + +#if 0 +#include <bitset> +#endif + +// defines how many states the bitfield can contain +// it has the size of 64 because I use a uInt64 +#define BITFIELDSIZE 64 + +using namespace ::utl; +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +class AccessibleStateSetHelperImpl +{ +public: + AccessibleStateSetHelperImpl(); + AccessibleStateSetHelperImpl(const AccessibleStateSetHelperImpl& rImpl); + ~AccessibleStateSetHelperImpl(); + + sal_Bool IsEmpty () + throw (uno::RuntimeException); + sal_Bool Contains (sal_Int16 aState) + throw (uno::RuntimeException); + uno::Sequence<sal_Int16> GetStates() + throw (uno::RuntimeException); + void AddState(sal_Int16 aState) + throw (uno::RuntimeException); + void RemoveState(sal_Int16 aState) + throw (uno::RuntimeException); + sal_Bool Compare(const AccessibleStateSetHelperImpl* pComparativeValue, + AccessibleStateSetHelperImpl* pOldStates, + AccessibleStateSetHelperImpl* pNewStates) + throw (uno::RuntimeException); + + inline void AddStates( const sal_Int64 _nStates ) SAL_THROW( ( ) ); + +private: +#if 0 + ::std::bitset<BITFIELDSIZE> maStates; //Bitfield +#endif + sal_uInt64 maStates; +}; + +AccessibleStateSetHelperImpl::AccessibleStateSetHelperImpl() + : maStates(0) +{ +} + +AccessibleStateSetHelperImpl::AccessibleStateSetHelperImpl(const AccessibleStateSetHelperImpl& rImpl) + : maStates(rImpl.maStates) +{ +} + +AccessibleStateSetHelperImpl::~AccessibleStateSetHelperImpl() +{ +} + +inline sal_Bool AccessibleStateSetHelperImpl::IsEmpty () + throw (uno::RuntimeException) +{ +#if 0 + return maStates.none(); +#endif + return maStates == 0; +} + +inline sal_Bool AccessibleStateSetHelperImpl::Contains (sal_Int16 aState) + throw (uno::RuntimeException) +{ + DBG_ASSERT(aState < BITFIELDSIZE, "the statesset is too small"); +#if 0 + return maStates.test(aState); +#endif + sal_uInt64 aTempBitSet(1); + aTempBitSet <<= aState; + return ((aTempBitSet & maStates) != 0); +} + +inline uno::Sequence<sal_Int16> AccessibleStateSetHelperImpl::GetStates() + throw (uno::RuntimeException) +{ + uno::Sequence<sal_Int16> aRet(BITFIELDSIZE); + sal_Int16* pSeq = aRet.getArray(); + sal_Int16 nStateCount(0); + for (sal_Int16 i = 0; i < BITFIELDSIZE; ++i) + if (Contains(i)) + { + *pSeq = i; + ++pSeq; + ++nStateCount; + } + aRet.realloc(nStateCount); + return aRet; +} + +inline void AccessibleStateSetHelperImpl::AddStates( const sal_Int64 _nStates ) SAL_THROW( ( ) ) +{ + maStates |= _nStates; +} + +inline void AccessibleStateSetHelperImpl::AddState(sal_Int16 aState) + throw (uno::RuntimeException) +{ + DBG_ASSERT(aState < BITFIELDSIZE, "the statesset is too small"); +#if 0 + maStates.set(aState); +#endif + sal_uInt64 aTempBitSet(1); + aTempBitSet <<= aState; + maStates |= aTempBitSet; +} + +inline void AccessibleStateSetHelperImpl::RemoveState(sal_Int16 aState) + throw (uno::RuntimeException) +{ + DBG_ASSERT(aState < BITFIELDSIZE, "the statesset is too small"); +#if 0 + maStates.set(aState, 0); +#endif + sal_uInt64 aTempBitSet(1); + aTempBitSet <<= aState; + aTempBitSet = ~aTempBitSet; + maStates &= aTempBitSet; +} + +inline sal_Bool AccessibleStateSetHelperImpl::Compare( + const AccessibleStateSetHelperImpl* pComparativeValue, + AccessibleStateSetHelperImpl* pOldStates, + AccessibleStateSetHelperImpl* pNewStates) + throw (uno::RuntimeException) +{ + sal_Bool bResult(sal_False); + if (pComparativeValue && pOldStates && pNewStates) + { + if (maStates == pComparativeValue->maStates) + bResult = sal_True; + else + { +#if 0 + std::bitset<BITFIELDSIZE> aTempBitSet(maStates); +#endif + sal_uInt64 aTempBitSet(maStates); + aTempBitSet ^= pComparativeValue->maStates; + pOldStates->maStates = aTempBitSet; + pOldStates->maStates &= maStates; + pNewStates->maStates = aTempBitSet; + pNewStates->maStates &= pComparativeValue->maStates; + } + } + return bResult; +} + + +//===== internal ============================================================ + +AccessibleStateSetHelper::AccessibleStateSetHelper () + : mpHelperImpl(NULL) +{ + mpHelperImpl = new AccessibleStateSetHelperImpl(); +} + +AccessibleStateSetHelper::AccessibleStateSetHelper ( const sal_Int64 _nInitialStates ) + : mpHelperImpl(NULL) +{ + mpHelperImpl = new AccessibleStateSetHelperImpl(); + mpHelperImpl->AddStates( _nInitialStates ); +} + +AccessibleStateSetHelper::AccessibleStateSetHelper (const AccessibleStateSetHelper& rHelper) + : cppu::WeakImplHelper1<XAccessibleStateSet>() + , mpHelperImpl(NULL) +{ + if (rHelper.mpHelperImpl) + mpHelperImpl = new AccessibleStateSetHelperImpl(*rHelper.mpHelperImpl); + else + mpHelperImpl = new AccessibleStateSetHelperImpl(); +} + +AccessibleStateSetHelper::~AccessibleStateSetHelper(void) +{ + delete mpHelperImpl; +} + +//===== XAccessibleStateSet ============================================== + + /** Checks whether the current state set is empty. + + @return + Returns <TRUE/> if there is no state in this state set and + <FALSE/> if there is at least one state set in it. + */ +sal_Bool SAL_CALL AccessibleStateSetHelper::isEmpty () + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->IsEmpty(); +} + + /** Checks if the given state is a member of the state set of this + object. + + @param aState + The state for which to check membership. This has to be one of + the constants of <type>AccessibleStateType</type>. + + @return + Returns <TRUE/> if the given state is a memeber of this object's + state set and <FALSE/> otherwise. + */ +sal_Bool SAL_CALL AccessibleStateSetHelper::contains (sal_Int16 aState) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->Contains(aState); +} + + /** Checks if all of the given states are in this object's state + set. + + @param aStateSet + This sequence of states is interpreted as set and every of its + members, duplicates are ignored, is checked for membership in + this object's state set. Each state has to be one of the + constants of <type>AccessibleStateType</type>. + + @return + Returns <TRUE/> if all states of the given state set are members + of this object's state set. <FALSE/> is returned if at least + one of the states in the given state is not a member of this + object's state set. + */ +sal_Bool SAL_CALL AccessibleStateSetHelper::containsAll + (const uno::Sequence<sal_Int16>& rStateSet) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + sal_Int32 nCount(rStateSet.getLength()); + const sal_Int16* pStates = rStateSet.getConstArray(); + sal_Int32 i = 0; + sal_Bool bFound(sal_True); + while (i < nCount) + { + bFound = mpHelperImpl->Contains(pStates[i]); + i++; + } + return bFound; +} + +uno::Sequence<sal_Int16> SAL_CALL AccessibleStateSetHelper::getStates() + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard(maMutex); + return mpHelperImpl->GetStates(); +} + +void AccessibleStateSetHelper::AddState(sal_Int16 aState) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + mpHelperImpl->AddState(aState); +} + +void AccessibleStateSetHelper::RemoveState(sal_Int16 aState) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + mpHelperImpl->RemoveState(aState); +} + +sal_Bool AccessibleStateSetHelper::Compare( + const AccessibleStateSetHelper& rComparativeValue, + AccessibleStateSetHelper& rOldStates, + AccessibleStateSetHelper& rNewStates) + throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + return mpHelperImpl->Compare(rComparativeValue.mpHelperImpl, + rOldStates.mpHelperImpl, rNewStates.mpHelperImpl); +} + +//===== XTypeProvider ======================================================= + +uno::Sequence< ::com::sun::star::uno::Type> + AccessibleStateSetHelper::getTypes (void) + throw (::com::sun::star::uno::RuntimeException) +{ + const ::com::sun::star::uno::Type aTypeList[] = { + ::getCppuType((const uno::Reference< + XAccessibleStateSet>*)0), + ::getCppuType((const uno::Reference< + lang::XTypeProvider>*)0) + }; + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> + aTypeSequence (aTypeList, 2); + return aTypeSequence; +} + +uno::Sequence<sal_Int8> SAL_CALL + AccessibleStateSetHelper::getImplementationId (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard (maMutex); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid ((sal_uInt8 *)aId.getArray(), 0, sal_True); + } + return aId; +} diff --git a/unotools/source/accessibility/makefile.mk b/unotools/source/accessibility/makefile.mk new file mode 100644 index 000000000000..7ed2e2bffe74 --- /dev/null +++ b/unotools/source/accessibility/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.10 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=accessibility + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/accessiblestatesethelper.obj \ + $(SLO)$/accessiblerelationsethelper.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/config/bootstrap.cxx b/unotools/source/config/bootstrap.cxx new file mode 100644 index 000000000000..d2a08a766e20 --- /dev/null +++ b/unotools/source/config/bootstrap.cxx @@ -0,0 +1,915 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bootstrap.cxx,v $ + * $Revision: 1.28.16.1 $ + * + * 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_unotools.hxx" + +#include <stdio.h> + +#include "unotools/bootstrap.hxx" + +// --------------------------------------------------------------------------------------- +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/file.hxx> +#include <osl/mutex.hxx> +#include <osl/diagnose.h> +// --------------------------------------------------------------------------------------- +#include <rtl/bootstrap.hxx> +#include <osl/process.h> // for osl_getExecutableFile +#include "tools/getprocessworkingdir.hxx" + +// --------------------------------------------------------------------------------------- +// #define this to a non-zero value, if remembering defaults is not supported properly +#define RTL_BOOTSTRAP_DEFAULTS_BROKEN 1 + +// --------------------------------------------------------------------------------------- +#define BOOTSTRAP_DATA_NAME SAL_CONFIGFILE("bootstrap") + +#define BOOTSTRAP_ITEM_PRODUCT_KEY "ProductKey" +#define BOOTSTRAP_ITEM_PRODUCT_SOURCE "ProductSource" +#define BOOTSTRAP_ITEM_VERSIONFILE "Location" +#define BOOTSTRAP_ITEM_BUILDID "buildid" + +#define BOOTSTRAP_ITEM_BASEINSTALLATION "BaseInstallation" +#define BOOTSTRAP_ITEM_USERINSTALLATION "UserInstallation" + +#define BOOTSTRAP_ITEM_SHAREDIR "SharedDataDir" +#define BOOTSTRAP_ITEM_USERDIR "UserDataDir" + +#define BOOTSTRAP_DEFAULT_BASEINSTALL "$SYSBINDIR/.." + +#define BOOTSTRAP_DIRNAME_SHAREDIR "share" +#define BOOTSTRAP_DIRNAME_USERDIR "user" + +#define VERSIONFILE_SECTION "Versions" + +#define SETUP_DATA_NAME SAL_CONFIGFILE("setup") +#define SETUP_ITEM_ALLUSERS "ALLUSERS" +// --------------------------------------------------------------------------------------- +typedef char const * AsciiString; +// --------------------------------------------------------------------------------------- + +namespace utl +{ +// --------------------------------------------------------------------------------------- + using ::rtl::OUString; + using ::rtl::OUStringBuffer; + using ::rtl::OString; + +// --------------------------------------------------------------------------------------- +// Implementation class: Bootstrap::Impl +// --------------------------------------------------------------------------------------- + + class Bootstrap::Impl + { + OUString const m_aImplName; + public: // struct to cache the result of a path lookup + struct PathData + { + OUString path; + PathStatus status; + + PathData() + : path() + , status(DATA_UNKNOWN) + {} + }; + public: // data members + // base install data + PathData aBaseInstall_; + + // user install data + PathData aUserInstall_; + + // INI files + PathData aBootstrapINI_; + PathData aVersionINI_; + + // overall status + Status status_; + + public: // construction and initialization + explicit + Impl(OUString const& _aImplName) + : m_aImplName(_aImplName) + { + status_ = initialize(); + } + + Status initialize(); + + // access helper + OUString getBootstrapValue(OUString const& _sName, OUString const& _sDefault) const; + sal_Bool getVersionValue(OUString const& _sName, OUString& _rValue, OUString const& _sDefault) const; + + OUString getImplName() const { return m_aImplName; } + + private: // implementation + bool initBaseInstallationData(rtl::Bootstrap& _rData); + bool initUserInstallationData(rtl::Bootstrap& _rData); + }; +// --------------------------------------------------------------------------------------- + static OUString getExecutableDirectory(); +// --------------------------------------------------------------------------------------- + + static Bootstrap::Impl* s_pData = NULL; + + Bootstrap::Impl const& Bootstrap::data() + { + + if (!s_pData) + { + using namespace osl; + MutexGuard aGuard( Mutex::getGlobalMutex() ); + + // static Impl s_theData(getExecutableDirectory() + OUString(RTL_CONSTASCII_USTRINGPARAM("/"BOOTSTRAP_DATA_NAME))); + // s_pData = &s_theData; + rtl::OUString uri; + rtl::Bootstrap::get( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BRAND_BASE_DIR")), uri); + s_pData = new Impl(uri + OUString(RTL_CONSTASCII_USTRINGPARAM("/program/"BOOTSTRAP_DATA_NAME))); + } + return *s_pData; + } + + void Bootstrap::reloadData() + { + if (s_pData != NULL) { + delete s_pData; + s_pData = NULL; + } + } + +// --------------------------------------------------------------------------------------- +// helper +// --------------------------------------------------------------------------------------- + +typedef Bootstrap::PathStatus PathStatus; + +sal_Unicode const cURLSeparator = '/'; + +// --------------------------------------------------------------------------------------- +static +inline +OUString getURLSeparator() +{ + static OUString theSep(&cURLSeparator,1); + return theSep; +} + +// --------------------------------------------------------------------------------------- +// path status utility function +static +PathStatus implCheckStatusOfURL(OUString const& _sURL, osl::DirectoryItem& aDirItem) +{ + using namespace osl; + + PathStatus eStatus = Bootstrap::DATA_UNKNOWN; + + if (_sURL.getLength() != 0) + { + switch( DirectoryItem::get(_sURL, aDirItem) ) + { + case DirectoryItem::E_None: // Success + eStatus = Bootstrap::PATH_EXISTS; + break; + + case DirectoryItem::E_NOENT: // No such file or directory<br> + eStatus = Bootstrap::PATH_VALID; + break; + + case DirectoryItem::E_INVAL: // the format of the parameters was not valid<br> + case DirectoryItem::E_NAMETOOLONG: // File name too long<br> + case DirectoryItem::E_NOTDIR: // A component of the path prefix of path is not a directory<p> + eStatus = Bootstrap::DATA_INVALID; + break; + + // how to handle these ? + case DirectoryItem::E_LOOP: // Too many symbolic links encountered<br> + case DirectoryItem::E_ACCES: // permission denied<br> + // any other error - what to do ? + default: + eStatus = Bootstrap::DATA_UNKNOWN; + break; + } + } + else + eStatus = Bootstrap::DATA_MISSING; + + return eStatus; +} +// --------------------------------------------------------------------------------------- + +static +bool implNormalizeURL(OUString & _sURL, osl::DirectoryItem& aDirItem) +{ + using namespace osl; + + OSL_PRECOND(aDirItem.is(), "Opened DirItem required"); + + static const sal_uInt32 cFileStatusMask = FileStatusMask_FileURL; + + FileStatus aFileStatus(cFileStatusMask); + + if (aDirItem.getFileStatus(aFileStatus) != DirectoryItem::E_None) + return false; + + OUString aNormalizedURL = aFileStatus.getFileURL(); + + if (aNormalizedURL.getLength() == 0) + return false; + + // #109863# sal/osl returns final slash for file URLs contradicting + // the URL/URI RFCs. + if ( aNormalizedURL.getStr()[aNormalizedURL.getLength()-1] != cURLSeparator ) + _sURL = aNormalizedURL; + else + _sURL = aNormalizedURL.copy( 0, aNormalizedURL.getLength()-1 ); + + return true; +} +// --------------------------------------------------------------------------------------- +static +bool implEnsureAbsolute(OUString & _rsURL) // also strips embedded dots !! +{ + using osl::File; + + OUString sBasePath; + OSL_VERIFY(tools::getProcessWorkingDir(&sBasePath)); + + OUString sAbsolute; + if ( File::E_None == File::getAbsoluteFileURL(sBasePath, _rsURL, sAbsolute)) + { + _rsURL = sAbsolute; + return true; + } + else + { + OSL_ENSURE(false, "Could not get absolute file URL for URL"); + return false; + } +} +/* old code to strip embedded dots + static OUString const sDots(RTL_CONSTASCII_USTRINGPARAM("/..")); + + sal_Int32 nDotsIndex = _rsURL.indexOf(sDots); + while (nDotsIndex >= 0) + { + OSL_ASSERT(_rsURL.indexOf(sDots) == nDotsIndex); + + sal_Int32 nStripIndex = _rsURL.lastIndexOf(cURLSeparator,nDotsIndex); + if (nStripIndex < 0 || nStripIndex+1 == nDotsIndex) + { + OSL_TRACE("Invalid use of dots in bootstrap URL"); + return false; + } + _rsURL = _rsURL.copy(0,nStripIndex) + _rsURL.copy(nDotsIndex + sDots.getLength()); + + nDotsIndex = _rsURL.indexOf(sDots,nStripIndex); + } + return true; +} + +*/ +// --------------------------------------------------------------------------------------- + +static +bool implMakeAbsoluteURL(OUString & _rsPathOrURL) +{ + using namespace osl; + + bool bURL; + + OUString sOther; + // check if it already was normalized + if ( File::E_None == File::getSystemPathFromFileURL(_rsPathOrURL, sOther) ) + { + bURL = true; + } + + else if ( File::E_None == File::getFileURLFromSystemPath(_rsPathOrURL, sOther) ) + { + _rsPathOrURL = sOther; + bURL = true; + } + else + bURL = false; + + return bURL && implEnsureAbsolute(_rsPathOrURL); +} +// --------------------------------------------------------------------------------------- +#if OSL_DEBUG_LEVEL > 0 +static +PathStatus dbgCheckStatusOfURL(OUString const& _sURL) +{ + using namespace osl; + + DirectoryItem aDirItem; + + return implCheckStatusOfURL(_sURL,aDirItem); +} +// --------------------------------------------------------------------------------------- +#endif + +static +PathStatus checkStatusAndNormalizeURL(OUString & _sURL) +{ + using namespace osl; + + PathStatus eStatus = Bootstrap::DATA_UNKNOWN; + + if (_sURL.getLength() == 0) + eStatus = Bootstrap::DATA_MISSING; + + else if ( !implMakeAbsoluteURL(_sURL) ) + eStatus = Bootstrap::DATA_INVALID; + + else + { + DirectoryItem aDirItem; + + eStatus = implCheckStatusOfURL(_sURL,aDirItem); + + if (eStatus == Bootstrap::PATH_EXISTS) + { + if (!implNormalizeURL(_sURL,aDirItem)) + OSL_ENSURE(false,"Unexpected failure getting actual URL for existing object"); + } + } + return eStatus; +} + + +// ---------------------------------------------------------------------------------- +// helpers to build and check a nested URL +static +PathStatus getDerivedPath( + OUString& _rURL, + OUString const& _aBaseURL, PathStatus _aBaseStatus, + OUString const& _sRelativeURL, + rtl::Bootstrap& _rData, OUString const& _sBootstrapParameter + ) +{ + OUString sDerivedURL; + + OSL_PRECOND(!_rData.getFrom(_sBootstrapParameter,sDerivedURL),"Setting for derived path is already defined"); + OSL_PRECOND(_sRelativeURL.getLength() != 0 && _sRelativeURL[0] != cURLSeparator,"Invalid Relative URL"); + + PathStatus aStatus = _aBaseStatus; + + // do we have a base path ? + if (_aBaseURL.getLength()) + { + OSL_PRECOND(_aBaseURL[_aBaseURL.getLength()-1] != cURLSeparator,"Unexpected: base URL ends in slash"); + + sDerivedURL = _aBaseURL + getURLSeparator() + _sRelativeURL; + + // a derived (nested) URL can only exist or have a lesser status, if the parent exists + if (aStatus == Bootstrap::PATH_EXISTS) + aStatus = checkStatusAndNormalizeURL(sDerivedURL); + + else // the relative appendix must be valid + OSL_ASSERT(aStatus != Bootstrap::PATH_VALID || dbgCheckStatusOfURL(sDerivedURL) == Bootstrap::PATH_VALID); + + _rData.getFrom(_sBootstrapParameter, _rURL, sDerivedURL); + + OSL_ENSURE(sDerivedURL == _rURL,"Could not set derived URL via Bootstrap default parameter"); + OSL_POSTCOND(RTL_BOOTSTRAP_DEFAULTS_BROKEN || + _rData.getFrom(_sBootstrapParameter,sDerivedURL) && sDerivedURL==_rURL,"Use of default did not affect bootstrap value"); + } + else + { + // clear the result + _rURL = _aBaseURL; + + // if we have no data it can't be a valid path + OSL_ASSERT( aStatus > Bootstrap::PATH_VALID ); + } + + + return aStatus; +} + +// ---------------------------------------------------------------------------------- +static +inline +PathStatus getDerivedPath( + OUString& _rURL, + Bootstrap::Impl::PathData const& _aBaseData, + OUString const& _sRelativeURL, + rtl::Bootstrap& _rData, OUString const& _sBootstrapParameter + ) +{ + return getDerivedPath(_rURL,_aBaseData.path,_aBaseData.status,_sRelativeURL,_rData,_sBootstrapParameter); +} + +// --------------------------------------------------------------------------------------- + +static +OUString getExecutableBaseName() +{ + OUString sExecutable; + + if (osl_Process_E_None == osl_getExecutableFile(&sExecutable.pData)) + { + // split the executable name + sal_Int32 nSepIndex = sExecutable.lastIndexOf(cURLSeparator); + + sExecutable = sExecutable.copy(nSepIndex + 1); + + // ... and get the basename (strip the extension) + sal_Unicode const cExtensionSep = '.'; + + sal_Int32 const nExtIndex = sExecutable.lastIndexOf(cExtensionSep); + sal_Int32 const nExtLength = sExecutable.getLength() - nExtIndex - 1; + if (0 < nExtIndex && nExtLength < 4) + sExecutable = sExecutable.copy(0,nExtIndex); + } + else + OSL_TRACE("Cannot get executable name: osl_getExecutableFile failed\n"); + + return sExecutable; +} + +// --------------------------------------------------------------------------------------- +static +OUString getExecutableDirectory() +{ + OUString sFileName; + OSL_VERIFY(osl_Process_E_None == osl_getExecutableFile(&sFileName.pData)); + + sal_Int32 nDirEnd = sFileName.lastIndexOf(cURLSeparator); + + OSL_ENSURE(nDirEnd >= 0, "Cannot locate executable directory"); + + return sFileName.copy(0,nDirEnd); +} + +// ---------------------------------------------------------------------------------- + +static +inline +Bootstrap::PathStatus updateStatus(Bootstrap::Impl::PathData & _rResult) +{ + return _rResult.status = checkStatusAndNormalizeURL(_rResult.path); +} +// --------------------------------------------------------------------------------------- + +static +Bootstrap::PathStatus implGetBootstrapFile(rtl::Bootstrap& _rData, Bootstrap::Impl::PathData & _rBootstrapFile) +{ + _rData.getIniName(_rBootstrapFile.path); + + return updateStatus(_rBootstrapFile); +} +// --------------------------------------------------------------------------------------- + +static +Bootstrap::PathStatus implGetVersionFile(rtl::Bootstrap& _rData, Bootstrap::Impl::PathData & _rVersionFile) +{ + OUString const csVersionFileItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_VERSIONFILE)); + + _rData.getFrom(csVersionFileItem,_rVersionFile.path); + + return updateStatus(_rVersionFile); +} +// --------------------------------------------------------------------------------------- +// Error reporting + +static char const IS_MISSING[] = "is missing"; +static char const IS_INVALID[] = "is corrupt"; +static char const PERIOD[] = ". "; + +// --------------------------------------------------------------------------------------- +static void addFileError(OUStringBuffer& _rBuf, OUString const& _aPath, AsciiString _sWhat) +{ + OUString sSimpleFileName = _aPath.copy(1 +_aPath.lastIndexOf(cURLSeparator)); + + _rBuf.appendAscii("The configuration file"); + _rBuf.appendAscii(" '").append(sSimpleFileName).appendAscii("' "); + _rBuf.appendAscii(_sWhat).appendAscii(PERIOD); +} +// --------------------------------------------------------------------------------------- + +static void addMissingDirectoryError(OUStringBuffer& _rBuf, OUString const& _aPath) +{ + _rBuf.appendAscii("The configuration directory"); + _rBuf.appendAscii(" '").append(_aPath).appendAscii("' "); + _rBuf.appendAscii(IS_MISSING).appendAscii(PERIOD); +} +// --------------------------------------------------------------------------------------- + +static void addUnexpectedError(OUStringBuffer& _rBuf, AsciiString _sExtraInfo = NULL) +{ + if (NULL == _sExtraInfo) + _sExtraInfo = "An internal failure occurred"; + + _rBuf.appendAscii(_sExtraInfo).appendAscii(PERIOD); +} +// --------------------------------------------------------------------------------------- + +static Bootstrap::FailureCode describeError(OUStringBuffer& _rBuf, Bootstrap::Impl const& _rData) +{ + Bootstrap::FailureCode eErrCode = Bootstrap::INVALID_BOOTSTRAP_DATA; + + _rBuf.appendAscii("The program cannot be started. "); + + switch (_rData.aUserInstall_.status) + { + case Bootstrap::PATH_EXISTS: + switch (_rData.aBaseInstall_.status) + { + case Bootstrap::PATH_VALID: + addMissingDirectoryError(_rBuf, _rData.aBaseInstall_.path); + eErrCode = Bootstrap::MISSING_INSTALL_DIRECTORY; + break; + + case Bootstrap::DATA_INVALID: + addUnexpectedError(_rBuf,"The installation path is invalid"); + break; + + case Bootstrap::DATA_MISSING: + addUnexpectedError(_rBuf,"The installation path is not available"); + break; + + case Bootstrap::PATH_EXISTS: // seems to be all fine (?) + addUnexpectedError(_rBuf,""); + break; + + default: OSL_ASSERT(false); + addUnexpectedError(_rBuf); + break; + } + break; + + case Bootstrap::PATH_VALID: + addMissingDirectoryError(_rBuf, _rData.aUserInstall_.path); + eErrCode = Bootstrap::MISSING_USER_DIRECTORY; + break; + + // else fall through + case Bootstrap::DATA_INVALID: + if (_rData.aVersionINI_.status == Bootstrap::PATH_EXISTS) + { + addFileError(_rBuf, _rData.aVersionINI_.path, IS_INVALID); + eErrCode = Bootstrap::INVALID_VERSION_FILE_ENTRY; + break; + } + // else fall through + + case Bootstrap::DATA_MISSING: + switch (_rData.aVersionINI_.status) + { + case Bootstrap::PATH_EXISTS: + addFileError(_rBuf, _rData.aVersionINI_.path, "does not support the current version"); + eErrCode = Bootstrap::MISSING_VERSION_FILE_ENTRY; + break; + + case Bootstrap::PATH_VALID: + addFileError(_rBuf, _rData.aVersionINI_.path, IS_MISSING); + eErrCode = Bootstrap::MISSING_VERSION_FILE; + break; + + default: + switch (_rData.aBootstrapINI_.status) + { + case Bootstrap::PATH_EXISTS: + addFileError(_rBuf, _rData.aBootstrapINI_.path, IS_INVALID); + + if (_rData.aVersionINI_.status == Bootstrap::DATA_MISSING) + eErrCode = Bootstrap::MISSING_BOOTSTRAP_FILE_ENTRY; + else + eErrCode = Bootstrap::INVALID_BOOTSTRAP_FILE_ENTRY; + break; + + case Bootstrap::DATA_INVALID: OSL_ASSERT(false); + case Bootstrap::PATH_VALID: + addFileError(_rBuf, _rData.aBootstrapINI_.path, IS_MISSING); + eErrCode = Bootstrap::MISSING_BOOTSTRAP_FILE; + break; + + default: + addUnexpectedError(_rBuf); + break; + } + break; + } + break; + + default: OSL_ASSERT(false); + addUnexpectedError(_rBuf); + break; + } + + return eErrCode; +} +// --------------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------------- +// class Bootstrap +// --------------------------------------------------------------------------------------- + +OUString Bootstrap::getProductKey() +{ + OUString const csProductKeyItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_PRODUCT_KEY)); + + OUString const sDefaultProductKey = getExecutableBaseName(); + + return data().getBootstrapValue( csProductKeyItem, sDefaultProductKey ); +} +// --------------------------------------------------------------------------------------- + +OUString Bootstrap::getProductKey(OUString const& _sDefault) +{ + OUString const csProductKeyItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_PRODUCT_KEY)); + + return data().getBootstrapValue( csProductKeyItem, _sDefault ); +} +// --------------------------------------------------------------------------------------- + +OUString Bootstrap::getProductSource(OUString const& _sDefault) +{ + OUString const csProductSourceItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_PRODUCT_SOURCE)); + + OUString sProductSource; + // read ProductSource from version.ini (versionrc) + data().getVersionValue( csProductSourceItem, sProductSource, _sDefault ); + return sProductSource; +} +// --------------------------------------------------------------------------------------- + +OUString Bootstrap::getBuildIdData(OUString const& _sDefault) +{ + OUString const csBuildIdItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_BUILDID)); + + OUString sBuildId; + // read buildid from version.ini (versionrc), if it doesn't exist or buildid is empty + if ( data().getVersionValue( csBuildIdItem, sBuildId, _sDefault ) != sal_True || + sBuildId.getLength() == 0 ) + // read buildid from bootstrap.ini (bootstraprc) + sBuildId = data().getBootstrapValue( csBuildIdItem, _sDefault ); + return sBuildId; +} +// --------------------------------------------------------------------------------------- + +OUString Bootstrap::getAllUsersValue(OUString const& _sDefault) +{ + OUString const csAllUsersItem(RTL_CONSTASCII_USTRINGPARAM(SETUP_ITEM_ALLUSERS)); + + rtl::Bootstrap aData( getExecutableDirectory() + OUString( RTL_CONSTASCII_USTRINGPARAM( "/"SETUP_DATA_NAME ) ) ); + OUString sResult; + aData.getFrom( csAllUsersItem, sResult, _sDefault ); + return sResult; +} +// --------------------------------------------------------------------------------------- + +Bootstrap::PathStatus Bootstrap::locateBaseInstallation(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aBaseInstall_; + + _rURL = aPathData.path; + return aPathData.status; +} +// --------------------------------------------------------------------------------------- + +PathStatus Bootstrap::locateUserInstallation(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aUserInstall_; + + _rURL = aPathData.path; + return aPathData.status; +} +// --------------------------------------------------------------------------------------- + +PathStatus Bootstrap::locateSharedData(OUString& _rURL) +{ + OUString const csShareDirItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_SHAREDIR)); + + rtl::Bootstrap aData( data().getImplName() ); + + if ( aData.getFrom(csShareDirItem, _rURL) ) + { + return checkStatusAndNormalizeURL(_rURL); + } + else + { + OUString const csShareDir(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DIRNAME_SHAREDIR)); + return getDerivedPath(_rURL, data().aBaseInstall_, csShareDir, aData, csShareDirItem); + } +} +// --------------------------------------------------------------------------------------- + +PathStatus Bootstrap::locateUserData(OUString& _rURL) +{ + OUString const csUserDirItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_USERDIR)); + + rtl::Bootstrap aData( data().getImplName() ); + + if ( aData.getFrom(csUserDirItem, _rURL) ) + { + return checkStatusAndNormalizeURL(_rURL); + } + else + { + OUString const csUserDir(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DIRNAME_USERDIR)); + return getDerivedPath(_rURL, data().aUserInstall_ ,csUserDir, aData, csUserDirItem); + } +} +// --------------------------------------------------------------------------------------- + +PathStatus Bootstrap::locateBootstrapFile(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aBootstrapINI_; + + _rURL = aPathData.path; + return aPathData.status; +} +// --------------------------------------------------------------------------------------- + +PathStatus Bootstrap::locateVersionFile(OUString& _rURL) +{ + Impl::PathData const& aPathData = data().aVersionINI_; + + _rURL = aPathData.path; + return aPathData.status; +} +// --------------------------------------------------------------------------------------- + +Bootstrap::Status Bootstrap::checkBootstrapStatus(OUString& _rDiagnosticMessage) +{ + FailureCode eDummyCode(NO_FAILURE); + + return checkBootstrapStatus(_rDiagnosticMessage,eDummyCode); +} +// --------------------------------------------------------------------------------------- + +Bootstrap::Status Bootstrap::checkBootstrapStatus(rtl::OUString& _rDiagnosticMessage, FailureCode& _rErrCode) +{ + Impl const& aData = data(); + + Status result = aData.status_; + + // maybe do further checks here + + OUStringBuffer sErrorBuffer; + if (result != DATA_OK) + _rErrCode = describeError(sErrorBuffer,aData); + + else + _rErrCode = NO_FAILURE; + + _rDiagnosticMessage = sErrorBuffer.makeStringAndClear(); + + return result; +} + +// --------------------------------------------------------------------------------------- +// class Bootstrap::Impl +// --------------------------------------------------------------------------------------- + +bool Bootstrap::Impl::initBaseInstallationData(rtl::Bootstrap& _rData) +{ + OUString const csBaseInstallItem( RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_BASEINSTALLATION) ); + OUString const csBaseInstallDefault( RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DEFAULT_BASEINSTALL) ); + + _rData.getFrom(csBaseInstallItem, aBaseInstall_.path, csBaseInstallDefault); + + bool bResult = (PATH_EXISTS == updateStatus(aBaseInstall_)); + + implGetBootstrapFile(_rData, aBootstrapINI_); + + return bResult; +} +// --------------------------------------------------------------------------------------- + +bool Bootstrap::Impl::initUserInstallationData(rtl::Bootstrap& _rData) +{ + OUString const csUserInstallItem( RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_USERINSTALLATION) ); + + if (_rData.getFrom(csUserInstallItem, aUserInstall_.path)) + { + updateStatus(aUserInstall_); + } + else + { + // should we do just this + aUserInstall_.status = DATA_MISSING; + + // .. or this - look for a single-user user directory ? + OUString const csUserDirItem(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_ITEM_USERDIR)); + OUString sDummy; + // look for $BASEINSTALLATION/user only if default UserDir setting is used + if (! _rData.getFrom(csUserDirItem, sDummy)) + { + OUString const csUserDir(RTL_CONSTASCII_USTRINGPARAM(BOOTSTRAP_DIRNAME_USERDIR)); + + if ( PATH_EXISTS == getDerivedPath(sDummy, aBaseInstall_, csUserDir, _rData, csUserDirItem) ) + aUserInstall_ = aBaseInstall_; + } + } + + bool bResult = (PATH_EXISTS == aUserInstall_.status); + + implGetVersionFile(_rData, aVersionINI_); + + return bResult; +} +// --------------------------------------------------------------------------------------- + +Bootstrap::Status Bootstrap::Impl::initialize() +{ + Bootstrap::Status result; + + rtl::Bootstrap aData( m_aImplName ); + + if (!initBaseInstallationData(aData)) + { + result = INVALID_BASE_INSTALL; + } + else if (!initUserInstallationData(aData)) + { + result = INVALID_USER_INSTALL; + + if (aUserInstall_.status >= DATA_MISSING) + { + switch (aVersionINI_.status) + { + case PATH_EXISTS: + case PATH_VALID: + result = MISSING_USER_INSTALL; + break; + + case DATA_INVALID: + case DATA_MISSING: + result = INVALID_BASE_INSTALL; + break; + default: + break; + } + } + } + else + { + result = DATA_OK; + } + return result; +} +// --------------------------------------------------------------------------------------- + +OUString Bootstrap::Impl::getBootstrapValue(OUString const& _sName, OUString const& _sDefault) const +{ + rtl::Bootstrap aData( m_aImplName ); + + OUString sResult; + aData.getFrom(_sName,sResult,_sDefault); + return sResult; +} +// --------------------------------------------------------------------------------------- + +sal_Bool Bootstrap::Impl::getVersionValue(OUString const& _sName, OUString& _rValue, OUString const& _sDefault) const +{ + // try to open version.ini (versionrc) + rtl::OUString uri; + rtl::Bootstrap::get( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BRAND_BASE_DIR")), uri); + rtl::Bootstrap aData( uri + + OUString(RTL_CONSTASCII_USTRINGPARAM("/program/"SAL_CONFIGFILE("version"))) ); + if ( aData.getHandle() == NULL ) + // version.ini (versionrc) doesn't exist + return sal_False; + + // read value + aData.getFrom(_sName,_rValue,_sDefault); + return sal_True; +} +// --------------------------------------------------------------------------------------- + +} // namespace utl + diff --git a/unotools/source/config/configitem.cxx b/unotools/source/config/configitem.cxx new file mode 100644 index 000000000000..a6b3bbaa1e2f --- /dev/null +++ b/unotools/source/config/configitem.cxx @@ -0,0 +1,1423 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: configitem.cxx,v $ + * $Revision: 1.52 $ + * + * 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_unotools.hxx" +#include "unotools/configitem.hxx" +#include "unotools/configmgr.hxx" +#include "unotools/configpathes.hxx" +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XChangesListener.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XHierarchicalName.hpp> +#include <com/sun/star/configuration/XTemplateContainer.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/util/XStringEscape.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <osl/diagnose.h> + +#include <rtl/ustrbuf.hxx> + +using namespace utl; +using rtl::OUString; +using rtl::OString; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::configuration; + +#define C2U(cChar) OUString::createFromAscii(cChar) +#include <cppuhelper/implbase1.hxx> // helper for implementations + +#ifdef DBG_UTIL +inline void lcl_CFG_DBG_EXCEPTION(const sal_Char* cText, const Exception& rEx) +{ + OString sMsg(cText); + sMsg += OString(rEx.Message.getStr(), rEx.Message.getLength(), RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); +} +#define CATCH_INFO(a) \ +catch(Exception& rEx) \ +{ \ + lcl_CFG_DBG_EXCEPTION(a, rEx);\ +} +#else + #define lcl_CFG_DBG_EXCEPTION( a, b) + #define CATCH_INFO(a) catch(Exception& ){} +#endif + +namespace utl{ + class ConfigChangeListener_Impl : public cppu::WeakImplHelper1 + < + com::sun::star::util::XChangesListener + > + { + ConfigItem* pParent; + const Sequence< OUString > aPropertyNames; + public: + ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames); + ~ConfigChangeListener_Impl(); + + //XChangesListener + virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) throw(RuntimeException); + + //XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException); + + }; +/* -----------------------------12.02.01 11:38-------------------------------- + + ---------------------------------------------------------------------------*/ +struct ConfigItem_Impl +{ + utl::ConfigManager* pManager; + sal_Int16 nMode; + sal_Bool bIsModified; + sal_Bool bEnableInternalNotification; + + sal_Int16 nInValueChange; + ConfigItem_Impl() : + pManager(0), + nMode(0), + bIsModified(sal_False), + bEnableInternalNotification(sal_False), + nInValueChange(0) + {} +}; +} +/* -----------------------------04.12.00 10:25-------------------------------- + + ---------------------------------------------------------------------------*/ +class ValueCounter_Impl +{ + sal_Int16& rCnt; +public: + ValueCounter_Impl(sal_Int16& rCounter): + rCnt(rCounter) + {rCnt++;} + ~ValueCounter_Impl() + { + OSL_ENSURE(rCnt>0, "RefCount < 0 ??"); + rCnt--; + } +}; +/* -----------------------------03.12.02 ------------------------------------- + + ---------------------------------------------------------------------------*/ +namespace +{ + // helper to achieve exception - safe handling of an Item under construction + template <class TYP> + class AutoDeleter // : Noncopyable + { + TYP* m_pItem; + public: + AutoDeleter(TYP * pItem) + : m_pItem(pItem) + { + } + + ~AutoDeleter() + { + delete m_pItem; + } + + void keep() { m_pItem = 0; } + }; +} +/* -----------------------------29.08.00 16:34-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigChangeListener_Impl::ConfigChangeListener_Impl( + ConfigItem& rItem, const Sequence< OUString >& rNames) : + pParent(&rItem), + aPropertyNames(rNames) +{ +} +/* -----------------------------29.08.00 16:34-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigChangeListener_Impl::~ConfigChangeListener_Impl() +{ +} +/* -----------------------------29.08.00 16:34-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool lcl_Find( + const rtl::OUString& rTemp, + const OUString* pCheckPropertyNames, + sal_Int32 nLength) +{ + //return true if the path is completely correct or if it is longer + //i.e ...Print/Content/Graphic and .../Print + for(sal_Int32 nIndex = 0; nIndex < nLength; nIndex++) + if( isPrefixOfConfigurationPath(rTemp, pCheckPropertyNames[nIndex]) ) + return sal_True; + return sal_False; +} +//----------------------------------------------------------------------------- +void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) throw(RuntimeException) +{ + const ElementChange* pElementChanges = rEvent.Changes.getConstArray(); + + Sequence<OUString> aChangedNames(rEvent.Changes.getLength()); + OUString* pNames = aChangedNames.getArray(); + + const OUString* pCheckPropertyNames = aPropertyNames.getConstArray(); + + sal_Int32 nNotify = 0; + for(int i = 0; i < aChangedNames.getLength(); i++) + { + OUString sTemp; + pElementChanges[i].Accessor >>= sTemp; + if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength())) + pNames[nNotify++] = sTemp; + } + if(nNotify) + { + aChangedNames.realloc(nNotify); + pParent->CallNotify(aChangedNames); + } +} +/* -----------------------------29.08.00 16:34-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException) +{ + pParent->RemoveChangesListener(); +} +/* -----------------------------29.08.00 12:50-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigItem::ConfigItem(const OUString rSubTree, sal_Int16 nSetMode ) : + sSubTree(rSubTree), + pImpl(new ConfigItem_Impl) +{ + AutoDeleter<ConfigItem_Impl> aNewImpl(pImpl); + + pImpl->pManager = ConfigManager::GetConfigManager(); + pImpl->nMode = nSetMode; + if(0 != (nSetMode&CONFIG_MODE_RELEASE_TREE)) + pImpl->pManager->AddConfigItem(*this); + else + m_xHierarchyAccess = pImpl->pManager->AddConfigItem(*this); + + // no more exceptions after c'tor has finished + aNewImpl.keep(); + pImpl->nMode &= ~CONFIG_MODE_PROPAGATE_ERRORS; +} +/* -----------------------------17.11.00 13:53-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigItem::ConfigItem(utl::ConfigManager& rManager, const rtl::OUString rSubTree) : + sSubTree(rSubTree), + pImpl(new ConfigItem_Impl) +{ + pImpl->pManager = &rManager; + pImpl->nMode = CONFIG_MODE_IMMEDIATE_UPDATE; // does not allow exceptions + m_xHierarchyAccess = pImpl->pManager->AddConfigItem(*this); +} +//--------------------------------------------------------------------- +//--- 02.08.2002 16:33:23 ----------------------------------------------- +sal_Bool ConfigItem::IsValidConfigMgr() const +{ + return ( pImpl->pManager && pImpl->pManager->GetConfigurationProvider().is() ); +} + +/* -----------------------------29.08.00 12:52-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigItem::~ConfigItem() +{ + if(pImpl->pManager) + { + RemoveChangesListener(); + pImpl->pManager->RemoveConfigItem(*this); + } + delete pImpl; +} +/* -----------------------------29.08.00 12:52-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::Commit() +{ + OSL_ENSURE(sal_False, "Base class called"); +} +/* -----------------------------29.08.00 12:52-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::ReleaseConfigMgr() +{ + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + try + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + xBatch->commitChanges(); + } + CATCH_INFO("Exception from commitChanges(): ") + } + RemoveChangesListener(); + OSL_ENSURE(pImpl->pManager, "ConfigManager already released"); + pImpl->pManager = 0; +} +/* -----------------------------29.08.00 12:52-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::CallNotify( const com::sun::star::uno::Sequence<OUString>& rPropertyNames ) +{ + if(!IsInValueChange() || pImpl->bEnableInternalNotification) + Notify(rPropertyNames); +} +/* -----------------------------29.08.00 12:52-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::Notify( const com::sun::star::uno::Sequence<OUString>& /*rPropertyNames*/) +{ + OSL_ENSURE(sal_False, "Base class called"); +} +/* -----------------------------12.12.00 17:09-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool lcl_IsLocalProperty(const OUString& rSubTree, const OUString& rProperty) +{ + static const sal_Char* aLocalProperties[] = + { + "Office.Common/Path/Current/Storage", + "Office.Common/Path/Current/Temp" + }; + static const int aLocalPropLen[] = + { + 34, + 31 + }; + OUString sProperty(rSubTree); + sProperty += C2U("/"); + sProperty += rProperty; + + if(sProperty.equalsAsciiL( aLocalProperties[0], aLocalPropLen[0]) || + sProperty.equalsAsciiL( aLocalProperties[1], aLocalPropLen[1])) + return sal_True; + + return sal_False; +} +/* -----------------------------10.04.01 15:00-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::impl_packLocalizedProperties( const Sequence< OUString >& lInNames , + const Sequence< Any >& lInValues , + Sequence< Any >& lOutValues ) +{ + // Safe impossible cases. + // This method should be called for special ConfigItem-mode only! + OSL_ENSURE( ((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_packLocalizedProperties()\nWrong call of this method detected!\n" ); + + sal_Int32 nSourceCounter ; // used to step during input lists + sal_Int32 nSourceSize ; // marks end of loop over input lists + sal_Int32 nDestinationCounter ; // actual position in output lists + sal_Int32 nPropertyCounter ; // counter of inner loop for Sequence< PropertyValue > + sal_Int32 nPropertiesSize ; // marks end of inner loop + Sequence< OUString > lPropertyNames ; // list of all locales for localized entry + Sequence< PropertyValue > lProperties ; // localized values of an configuration entry packed for return + Reference< XInterface > xLocalizedNode ; // if cfg entry is localized ... lInValues contains an XInterface! + + // Optimise follow algorithm ... A LITTLE BIT :-) + // There exist two different possibilities: + // i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues! + // ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues! + // ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service). + // We read all his child nodes and pack it into Sequence< PropertyValue >. + // The result list we pack into the return any. We never change size of lists! + nSourceSize = lInNames.getLength(); + lOutValues.realloc( nSourceSize ); + + // Algorithm: + // Copy all names and values from in to out lists. + // Look for special localized entries ... You can detect it as "XInterface" packed into an Any. + // Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >. + // Add this list to out lists then. + + nDestinationCounter = 0; + for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter ) + { + // If item a special localized one ... convert and pack it ... + if( lInValues[nSourceCounter].getValueTypeName() == C2U("com.sun.star.uno.XInterface") ) + { + lInValues[nSourceCounter] >>= xLocalizedNode; + Reference< XNameContainer > xSetAccess( xLocalizedNode, UNO_QUERY ); + if( xSetAccess.is() == sal_True ) + { + lPropertyNames = xSetAccess->getElementNames() ; + nPropertiesSize = lPropertyNames.getLength() ; + lProperties.realloc( nPropertiesSize ) ; + + for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter ) + { + #if OSL_DEBUG_LEVEL > 1 + // Sometimes it's better to see what's going on :-) + OUString sPropName = lInNames[nSourceCounter]; + OUString sLocaleName = lPropertyNames[nPropertyCounter]; + #endif + lProperties[nPropertyCounter].Name = lPropertyNames[nPropertyCounter] ; + OUString sLocaleValue; + xSetAccess->getByName( lPropertyNames[nPropertyCounter] ) >>= sLocaleValue ; + lProperties[nPropertyCounter].Value <<= sLocaleValue; + } + + lOutValues[nDestinationCounter] <<= lProperties; + } + } + // ... or copy normal items to return lists directly. + else + { + lOutValues[nDestinationCounter] = lInValues[nSourceCounter]; + } + ++nDestinationCounter; + } +} +/* -----------------------------10.04.01 15:00-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::impl_unpackLocalizedProperties( const Sequence< OUString >& lInNames , + const Sequence< Any >& lInValues , + Sequence< OUString >& lOutNames , + Sequence< Any >& lOutValues ) +{ + // Safe impossible cases. + // This method should be called for special ConfigItem-mode only! + OSL_ENSURE( ((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_unpackLocalizedProperties()\nWrong call of this method detected!\n" ); + + sal_Int32 nSourceCounter ; // used to step during input lists + sal_Int32 nSourceSize ; // marks end of loop over input lists + sal_Int32 nDestinationCounter ; // actual position in output lists + sal_Int32 nPropertyCounter ; // counter of inner loop for Sequence< PropertyValue > + sal_Int32 nPropertiesSize ; // marks end of inner loop + OUString sNodeName ; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" ) + Sequence< PropertyValue > lProperties ; // localized values of an configuration entry getted from lInValues-Any + + // Optimise follow algorithm ... A LITTLE BIT :-) + // There exist two different possibilities: + // i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues! + // ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues. + // => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast. + // We should reserve same space for output list like input ones first. + // Follow algorithm looks for these borders and change it for ii) only! + // It will be faster then a "realloc()" call in every loop ... + nSourceSize = lInNames.getLength(); + + lOutNames.realloc ( nSourceSize ); + lOutValues.realloc ( nSourceSize ); + + // Algorithm: + // Copy all names and values from const to return lists. + // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any. + // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues. + + nDestinationCounter = 0; + for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter ) + { + // If item a special localized one ... split it and insert his parts to output lists ... + if( lInValues[nSourceCounter].getValueType() == ::getCppuType( (const Sequence< PropertyValue >*)NULL ) ) + { + lInValues[nSourceCounter] >>= lProperties ; + sNodeName = lInNames[nSourceCounter] ; + sNodeName += C2U("/") ; + nPropertiesSize = lProperties.getLength() ; + + if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() ) + { + lOutNames.realloc ( nDestinationCounter+nPropertiesSize ); + lOutValues.realloc ( nDestinationCounter+nPropertiesSize ); + } + + for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter ) + { + lOutNames [nDestinationCounter] = sNodeName + lProperties[nPropertyCounter].Name ; + lOutValues[nDestinationCounter] = lProperties[nPropertyCounter].Value ; + ++nDestinationCounter; + } + } + // ... or copy normal items to return lists directly. + else + { + if( (nDestinationCounter+1) > lOutNames.getLength() ) + { + lOutNames.realloc ( nDestinationCounter+1 ); + lOutValues.realloc ( nDestinationCounter+1 ); + } + + lOutNames [nDestinationCounter] = lInNames [nSourceCounter]; + lOutValues[nDestinationCounter] = lInValues[nSourceCounter]; + ++nDestinationCounter; + } + } +} +/* -----------------------------03.02.2003 14:44------------------------------ + + ---------------------------------------------------------------------------*/ +Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence< rtl::OUString >& rNames) +{ + sal_Int32 i; + + // size of return list is fix! + // Every item must match to length of incoming name list. + sal_Int32 nCount = rNames.getLength(); + Sequence< sal_Bool > lStates(nCount); + + // We must be shure to return a valid information everytime! + // Set default to non readonly ... similar to the configuration handling of this property. + for ( i=0; i<nCount; ++i) + lStates[i] = sal_False; + + // no access - no informations ... + Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree(); + if (!xHierarchyAccess.is()) + return lStates; + + for (i=0; i<nCount; ++i) + { + try + { + if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, rNames[i])) + { + OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nlocal mode seams to be used!?\n"); + continue; + } + + OUString sName = rNames[i]; + OUString sPath; + OUString sProperty; + + ::utl::splitLastFromConfigurationPath(sName,sPath,sProperty); + if (!sPath.getLength() && !sProperty.getLength()) + { + OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nsplitt failed\n"); + continue; + } + + Reference< XInterface > xNode; + Reference< XPropertySet > xSet ; + Reference< XPropertySetInfo > xInfo; + if (sPath.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(sPath); + if (!(aNode >>= xNode) || !xNode.is()) + { + OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nno set available\n"); + continue; + } + } + else + { + xNode = Reference< XInterface >(xHierarchyAccess, UNO_QUERY); + } + + xSet = Reference< XPropertySet >(xNode, UNO_QUERY); + if (xSet.is()) + { + xInfo = xSet->getPropertySetInfo(); + OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n"); + } + else + { + xInfo = Reference< XPropertySetInfo >(xNode, UNO_QUERY); + OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n"); + } + + if (!xInfo.is()) + { + OSL_ENSURE(sal_False, "ConfigItem::IsReadonly()\nno prop info available\n"); + continue; + } + + Property aProp = xInfo->getPropertyByName(sProperty); + lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY); + } + catch(Exception&){} + } + + return lStates; +} + +/* -----------------------------29.08.00 15:10-------------------------------- + + ---------------------------------------------------------------------------*/ +Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames) +{ + Sequence< Any > aRet(rNames.getLength()); + const OUString* pNames = rNames.getConstArray(); + Any* pRet = aRet.getArray(); + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + for(int i = 0; i < rNames.getLength(); i++) + { + try + { + if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, pNames[i])) + { + OUString sProperty(sSubTree); + sProperty += C2U("/"); + sProperty += pNames[i]; + pRet[i] = pImpl->pManager->GetLocalProperty(sProperty); + } + else + pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]); + } + #ifdef DBG_UTIL + catch(Exception& rEx) + { + OString sMsg("XHierarchicalNameAccess: "); + sMsg += OString(rEx.Message.getStr(), + rEx.Message.getLength(), + RTL_TEXTENCODING_ASCII_US); + sMsg += OString("\n"); + sMsg += OString(ConfigManager::GetConfigBaseURL().getStr(), + ConfigManager::GetConfigBaseURL().getLength(), + RTL_TEXTENCODING_ASCII_US); + sMsg += OString(sSubTree.getStr(), + sSubTree.getLength(), + RTL_TEXTENCODING_ASCII_US); + sMsg += OString("/"); + sMsg += OString(pNames[i].getStr(), + pNames[i].getLength(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); + } +#else + catch(Exception&){} +#endif + } + + // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >. + if((pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES) + { + Sequence< Any > lValues; + impl_packLocalizedProperties( rNames, aRet, lValues ); + aRet = lValues; + } + } + return aRet; +} +/* -----------------------------29.08.00 17:28-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::PutProperties( const Sequence< OUString >& rNames, + const Sequence< Any>& rValues) +{ + ValueCounter_Impl aCounter(pImpl->nInValueChange); + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY); + sal_Bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is(); + if(bRet) + { + Sequence< OUString > lNames ; + Sequence< Any > lValues ; + const OUString* pNames = NULL ; + const Any* pValues = NULL ; + sal_Int32 nNameCount ; + if(( pImpl->nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES ) + { + // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue > + // as value of an localized configuration entry! + // How we can do that? + // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"! + impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues ); + pNames = lNames.getConstArray (); + pValues = lValues.getConstArray (); + nNameCount = lNames.getLength (); + } + else + { + // This is the normal mode ... + // Use given input lists directly. + pNames = rNames.getConstArray (); + pValues = rValues.getConstArray (); + nNameCount = rNames.getLength (); + } + for(int i = 0; i < nNameCount; i++) + { + if(pImpl->pManager->IsLocalConfigProvider() && lcl_IsLocalProperty(sSubTree, pNames[i])) + { + OUString sProperty(sSubTree); + sProperty += C2U("/"); + sProperty += pNames[i]; + pImpl->pManager->PutLocalProperty(sProperty, pValues[i]); + } + else + { + try + { + OUString sNode, sProperty; + if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty)) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(sNode); + + Reference<XNameAccess> xNodeAcc; + aNode >>= xNodeAcc; + Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY); + Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY); + + sal_Bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty)); + if (bExist && xNodeReplace.is()) + xNodeReplace->replaceByName(sProperty, pValues[i]); + else + if (!bExist && xNodeCont.is()) + xNodeCont->insertByName(sProperty, pValues[i]); + else + bRet = sal_False; + } + else //direct value + { + xTopNodeReplace->replaceByName(sProperty, pValues[i]); + } + } + CATCH_INFO("Exception from PutProperties: "); + } + } + try + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + xBatch->commitChanges(); + } + CATCH_INFO("Exception from commitChanges(): ") + } + + return bRet; +} +/* -----------------------------08.12.05 15:27-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::DisableNotification() +{ + OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" ); + RemoveChangesListener(); +} +/* -----------------------------29.08.00 16:19-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames, + sal_Bool bEnableInternalNotification ) + +{ + OSL_ENSURE(0 == (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "notification in CONFIG_MODE_RELEASE_TREE mode not possible"); + pImpl->bEnableInternalNotification = bEnableInternalNotification; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY); + if(!xChgNot.is()) + return sal_False; + + OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called"); + if(xChangeLstnr.is()) + xChgNot->removeChangesListener( xChangeLstnr ); + sal_Bool bRet = sal_True; + + try + { + xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames); + xChgNot->addChangesListener( xChangeLstnr ); + } + catch(RuntimeException& ) + { + bRet = sal_False; + } + return bRet; +} +/* -----------------------------29.08.00 16:47-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::RemoveChangesListener() +{ + Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY); + if(xChgNot.is() && xChangeLstnr.is()) + { + try + { + xChgNot->removeChangesListener( xChangeLstnr ); + xChangeLstnr = 0; + } + catch(Exception & ) + { + } + } +} +/* -----------------------------10.07.00 -------------------------------- + + ---------------------------------------------------------------------------*/ +void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode) +{ + switch (_eFormat) + { + case CONFIG_NAME_LOCAL_NAME: + // unaltered - this is our input format + break; + + case CONFIG_NAME_FULL_PATH: + { + Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY); + if (xFormatter.is()) + { + OUString * pNames = _rNames.getArray(); + for(int i = 0; i<_rNames.getLength(); ++i) + try + { + pNames[i] = xFormatter->composeHierarchicalName(pNames[i]); + } + CATCH_INFO("Exception from composeHierarchicalName(): ") + break; + } + } + OSL_ENSURE(false, "Cannot create absolute pathes: missing interface"); + // make local pathes instaed + + case CONFIG_NAME_LOCAL_PATH: + { + Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY); + if (xTypeContainer.is()) + { + OUString sTypeName = xTypeContainer->getElementTemplateName(); + sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1); + + OUString * pNames = _rNames.getArray(); + for(int i = 0; i<_rNames.getLength(); ++i) + { + pNames[i] = wrapConfigurationElementName(pNames[i],sTypeName); + } + } + else + { + static const OUString sSetService(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.SetAccess")); + Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY); + if (xSVI.is() && xSVI->supportsService(sSetService)) + { + OUString * pNames = _rNames.getArray(); + for(int i = 0; i<_rNames.getLength(); ++i) + { + pNames[i] = wrapConfigurationElementName(pNames[i]); + } + } + } + } + break; + + case CONFIG_NAME_PLAINTEXT_NAME: + { + Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY); + if (xEscaper.is()) + { + OUString * pNames = _rNames.getArray(); + for(int i = 0; i<_rNames.getLength(); ++i) + try + { + pNames[i] = xEscaper->unescapeString(pNames[i]); + } + CATCH_INFO("Exception from unescapeString(): ") + } + } + break; + + } +} +/* -----------------------------10.07.00 -------------------------------- + + ---------------------------------------------------------------------------*/ +Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode) +{ + ConfigNameFormat const eDefaultFormat = CONFIG_NAME_LOCAL_NAME; // CONFIG_NAME_DEFAULT; + + return GetNodeNames(rNode, eDefaultFormat); +} +/* -----------------------------15.09.00 12:06-------------------------------- + + ---------------------------------------------------------------------------*/ +Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat) +{ + Sequence< OUString > aRet; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + try + { + Reference<XNameAccess> xCont; + if(rNode.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY); + if(xCont.is()) + { + aRet = xCont->getElementNames(); + lcl_normalizeLocalNames(aRet,eFormat,xCont); + } + + } + CATCH_INFO("Exception from GetNodeNames: "); + } + return aRet; +} +/* -----------------------------15.09.00 15:52-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::ClearNodeSet(const OUString& rNode) +{ + ValueCounter_Impl aCounter(pImpl->nInValueChange); + sal_Bool bRet = sal_False; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + try + { + Reference<XNameContainer> xCont; + if(rNode.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return sal_False; + Sequence< OUString > aNames = xCont->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + for(sal_Int32 i = 0; i < aNames.getLength(); i++) + { + try + { + xCont->removeByName(pNames[i]); + } + CATCH_INFO("Exception from removeByName(): ") + } + xBatch->commitChanges(); + bRet = sal_True; + } + CATCH_INFO("Exception from ClearNodeSet") + } + return bRet; +} +/* -----------------------------24.11.00 10:58-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements) +{ + ValueCounter_Impl aCounter(pImpl->nInValueChange); + sal_Bool bRet = sal_False; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + const OUString* pElements = rElements.getConstArray(); + try + { + Reference<XNameContainer> xCont; + if(rNode.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return sal_False; + try + { + for(sal_Int32 nElement = 0; nElement < rElements.getLength(); nElement++) + { + xCont->removeByName(pElements[nElement]); + } + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + xBatch->commitChanges(); + } + CATCH_INFO("Exception from commitChanges(): ") + bRet = sal_True; + } + CATCH_INFO("Exception from GetNodeNames: ") + } + return bRet; +} +//---------------------------------------------------------------------------- +static inline +OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix ) +{ + OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix); + return extractFirstFromConfigurationPath( sSubPath ); +} +//---------------------------------------------------------------------------- +static +Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix ) +{ + const PropertyValue* pProperties = rValues.getConstArray(); + + Sequence< OUString > aSubNodeNames(rValues.getLength()); + OUString* pSubNodeNames = aSubNodeNames.getArray(); + + OUString sLastSubNode; + sal_Int32 nSubIndex = 0; + + for(sal_Int32 i = 0; i < rValues.getLength(); i++) + { + OUString const sSubPath = dropPrefixFromConfigurationPath( pProperties[i].Name, rPrefix); + OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath ); + + if(sLastSubNode != sSubNode) + { + pSubNodeNames[nSubIndex++] = sSubNode; + } + + sLastSubNode = sSubNode; + } + aSubNodeNames.realloc(nSubIndex); + + return aSubNodeNames; +} +/* -----------------------------15.09.00 15:52-------------------------------- + add or change properties + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::SetSetProperties( + const OUString& rNode, Sequence< PropertyValue > rValues) +{ + ValueCounter_Impl aCounter(pImpl->nInValueChange); + sal_Bool bRet = sal_True; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + try + { + Reference<XNameContainer> xCont; + if(rNode.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return sal_False; + + Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); + + if(xFac.is()) + { + const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode); + + const sal_Int32 nSubNodeCount = aSubNodeNames.getLength(); + + for(sal_Int32 j = 0; j <nSubNodeCount ; j++) + { + if(!xCont->hasByName(aSubNodeNames[j])) + { + Reference<XInterface> xInst = xFac->createInstance(); + Any aVal; aVal <<= xInst; + xCont->insertByName(aSubNodeNames[j], aVal); + } + //set values + } + try + { + xBatch->commitChanges(); + } + CATCH_INFO("Exception from commitChanges(): ") + + const PropertyValue* pProperties = rValues.getConstArray(); + + Sequence< OUString > aSetNames(rValues.getLength()); + OUString* pSetNames = aSetNames.getArray(); + + Sequence< Any> aSetValues(rValues.getLength()); + Any* pSetValues = aSetValues.getArray(); + + sal_Bool bEmptyNode = rNode.getLength() == 0; + for(sal_Int32 k = 0; k < rValues.getLength(); k++) + { + pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0); + pSetValues[k] = pProperties[k].Value; + } + bRet = PutProperties(aSetNames, aSetValues); + } + else + { + //if no factory is available then the node contains basic data elements + const PropertyValue* pValues = rValues.getConstArray(); + for(int nValue = 0; nValue < rValues.getLength();nValue++) + { + try + { + OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode ); + + if(xCont->hasByName(sSubNode)) + xCont->replaceByName(sSubNode, pValues[nValue].Value); + else + xCont->insertByName(sSubNode, pValues[nValue].Value); + + OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(pValues[nValue].Name), + "Invalid config path" ); + } + CATCH_INFO("Exception form insert/replaceByName(): ") + } + xBatch->commitChanges(); + } + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx); +#else + catch(Exception&) + { +#endif + bRet = sal_False; + } + } + return bRet; +} +/* -----------------------------15.09.00 15:52-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::ReplaceSetProperties( + const OUString& rNode, Sequence< PropertyValue > rValues) +{ + ValueCounter_Impl aCounter(pImpl->nInValueChange); + sal_Bool bRet = sal_True; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + try + { + Reference<XNameContainer> xCont; + if(rNode.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return sal_False; + + // JB: Change: now the same name handling for sets of simple values + const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode); + const OUString* pSubNodeNames = aSubNodeNames.getConstArray(); + const sal_Int32 nSubNodeCount = aSubNodeNames.getLength(); + + Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); + const bool isSimpleValueSet = !xFac.is(); + + //remove unknown members first + { + const Sequence<OUString> aContainerSubNodes = xCont->getElementNames(); + const OUString* pContainerSubNodes = aContainerSubNodes.getConstArray(); + + for(sal_Int32 nContSub = 0; nContSub < aContainerSubNodes.getLength(); nContSub++) + { + sal_Bool bFound = sal_False; + for(sal_Int32 j = 0; j < nSubNodeCount; j++) + { + if(pSubNodeNames[j] == pContainerSubNodes[nContSub]) + { + bFound = sal_True; + break; + } + } + if(!bFound) + try + { + xCont->removeByName(pContainerSubNodes[nContSub]); + } + catch (Exception & ) + { + if (isSimpleValueSet) + try + { + // #i37322#: fallback action: replace with <void/> + xCont->replaceByName(pContainerSubNodes[nContSub], Any()); + // fallback successfull: continue looping + continue; + } + catch (Exception &) + {} // propagate original exception, if fallback fails + + throw; + } + } + try { xBatch->commitChanges(); } + CATCH_INFO("Exception from commitChanges(): ") + } + + if(xFac.is()) // !isSimpleValueSet + { + for(sal_Int32 j = 0; j < nSubNodeCount; j++) + { + if(!xCont->hasByName(pSubNodeNames[j])) + { + //create if not available + Reference<XInterface> xInst = xFac->createInstance(); + Any aVal; aVal <<= xInst; + xCont->insertByName(pSubNodeNames[j], aVal); + } + } + try { xBatch->commitChanges(); } + CATCH_INFO("Exception from commitChanges(): ") + + const PropertyValue* pProperties = rValues.getConstArray(); + + Sequence< OUString > aSetNames(rValues.getLength()); + OUString* pSetNames = aSetNames.getArray(); + + Sequence< Any> aSetValues(rValues.getLength()); + Any* pSetValues = aSetValues.getArray(); + + sal_Bool bEmptyNode = rNode.getLength() == 0; + for(sal_Int32 k = 0; k < rValues.getLength(); k++) + { + pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0); + pSetValues[k] = pProperties[k].Value; + } + bRet = PutProperties(aSetNames, aSetValues); + } + else + { + const PropertyValue* pValues = rValues.getConstArray(); + + //if no factory is available then the node contains basic data elements + for(int nValue = 0; nValue < rValues.getLength();nValue++) + { + try + { + OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode ); + + if(xCont->hasByName(sSubNode)) + xCont->replaceByName(sSubNode, pValues[nValue].Value); + else + xCont->insertByName(sSubNode, pValues[nValue].Value); + } + CATCH_INFO("Exception from insert/replaceByName(): "); + } + xBatch->commitChanges(); + } + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx); +#else + catch(Exception&) + { +#endif + bRet = sal_False; + } + } + return bRet; +} +/* -----------------------------07.05.01 12:15-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::getUniqueSetElementName( const ::rtl::OUString& _rSetNode, ::rtl::OUString& _rName) +{ + ::rtl::OUString sNewElementName; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + sal_Bool bRet = sal_False; + if(xHierarchyAccess.is()) + { + try + { + Reference< XNameAccess > xSetNode; + xHierarchyAccess->getByHierarchicalName(_rSetNode) >>= xSetNode; + if (xSetNode.is()) + { + const sal_uInt32 nPrime = 65521; // a prime number + const sal_uInt32 nPrimeLess2 = nPrime - 2; + sal_uInt32 nEngendering = (rand() % nPrimeLess2) + 2; // the engendering of the field + + // the element which will loop through the field + sal_uInt32 nFieldElement = nEngendering; + + for (; 1 != nFieldElement; nFieldElement = (nFieldElement * nEngendering) % nPrime) + { + ::rtl::OUString sThisRoundTrial = _rName; + sThisRoundTrial += ::rtl::OUString::valueOf((sal_Int32)nFieldElement); + + if (!xSetNode->hasByName(sThisRoundTrial)) + { + _rName = sThisRoundTrial; + bRet = sal_True; + break; + } + } + } + } + CATCH_INFO("Exception from getUniqueSetElementName(): ") + } + return bRet; +} +/* -----------------------------23.01.01 12:49-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::AddNode(const rtl::OUString& rNode, const rtl::OUString& rNewNode) +{ + ValueCounter_Impl aCounter(pImpl->nInValueChange); + sal_Bool bRet = sal_True; + Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree(); + if(xHierarchyAccess.is()) + { + Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY); + try + { + Reference<XNameContainer> xCont; + if(rNode.getLength()) + { + Any aNode = xHierarchyAccess->getByHierarchicalName(rNode); + aNode >>= xCont; + } + else + xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY); + if(!xCont.is()) + return sal_False; + + Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY); + + if(xFac.is()) + { + if(!xCont->hasByName(rNewNode)) + { + Reference<XInterface> xInst = xFac->createInstance(); + Any aVal; aVal <<= xInst; + xCont->insertByName(rNewNode, aVal); + } + try + { + xBatch->commitChanges(); + } + CATCH_INFO("Exception from commitChanges(): ") + } + else + { + //if no factory is available then the node contains basic data elements + try + { + if(!xCont->hasByName(rNewNode)) + xCont->insertByName(rNewNode, Any()); + } + CATCH_INFO("Exception from AddNode(): ") + } + xBatch->commitChanges(); + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx); +#else + catch(Exception&) + { +#endif + bRet = sal_False; + } + } + return bRet; +} +/* -----------------------------12.02.01 11:38-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Int16 ConfigItem::GetMode() const +{ + return pImpl->nMode; +} +/* -----------------------------12.02.01 13:31-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::SetModified() +{ + pImpl->bIsModified = sal_True; +} +/* -----------------------------05.05.01 14:07-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::ClearModified() +{ + pImpl->bIsModified = sal_False; +} +/* -----------------------------12.02.01 13:31-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::IsModified() const +{ + return pImpl->bIsModified; +} +/* -----------------------------12.02.01 13:33-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigItem::IsInValueChange() const +{ + return pImpl->nInValueChange > 0; +} +/* -----------------------------21.06.01 12:26-------------------------------- + + ---------------------------------------------------------------------------*/ +Reference< XHierarchicalNameAccess> ConfigItem::GetTree() +{ + Reference< XHierarchicalNameAccess> xRet; + if(!m_xHierarchyAccess.is()) + xRet = pImpl->pManager->AcquireTree(*this); + else + xRet = m_xHierarchyAccess; + OSL_ENSURE(xRet.is(), "AcquireTree failed"); + return xRet; +} +/* -----------------------------22.06.01 08:42-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::LockTree() +{ + OSL_ENSURE(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "call LockTree in CONFIG_MODE_RELEASE_TREE mode, only"); + m_xHierarchyAccess = GetTree(); +} +/* -----------------------------22.06.01 08:42-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigItem::UnlockTree() +{ + OSL_ENSURE(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE), "call UnlockTree in CONFIG_MODE_RELEASE_TREE mode, only"); + if(0 != (pImpl->nMode&CONFIG_MODE_RELEASE_TREE)) + m_xHierarchyAccess = 0; +} + + + diff --git a/unotools/source/config/configmgr.cxx b/unotools/source/config/configmgr.cxx new file mode 100644 index 000000000000..6a5d163871cd --- /dev/null +++ b/unotools/source/config/configmgr.cxx @@ -0,0 +1,735 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: configmgr.cxx,v $ + * $Revision: 1.47.14.1 $ + * + * 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_unotools.hxx" +#include "unotools/configmgr.hxx" +#include "unotools/configitem.hxx" +#include "unotools/configpathes.hxx" +#include <unotools/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <osl/diagnose.h> +#include <rtl/bootstrap.hxx> +#include <rtl/instance.hxx> +#if OSL_DEBUG_LEVEL > 0 +#include <rtl/strbuf.hxx> +#endif + +#include <list> + +//----------------------------------------------------------------------------- + +using namespace utl; +using namespace rtl; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; + +#define C2U(cChar) OUString::createFromAscii(cChar) +#define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) + +//----------------------------------------------------------------------------- +const char* cConfigBaseURL = "/org.openoffice."; +//const char* cConfigBaseURL = "/com.sun.star."; +const char* cAccessSrvc = "com.sun.star.configuration.ConfigurationUpdateAccess"; + +namespace +{ + struct BrandName + : public rtl::Static< ::rtl::OUString, BrandName > {}; + struct ProductVersion + : public rtl::Static< ::rtl::OUString, ProductVersion > {}; + struct AboutBoxProductVersion + : public rtl::Static< ::rtl::OUString, AboutBoxProductVersion > {}; + struct ProductExtension + : public rtl::Static< ::rtl::OUString, ProductExtension > {}; + struct XMLFileFormatName + : public rtl::Static< ::rtl::OUString, XMLFileFormatName > {}; + struct XMLFileFormatVersion + : public rtl::Static< ::rtl::OUString, XMLFileFormatVersion > {}; + struct WriterCompatibilityVersionOOo11 + : public rtl::Static< ::rtl::OUString, WriterCompatibilityVersionOOo11 > {}; + struct OpenSourceContext : public rtl::StaticWithInit< sal_Int32, OpenSourceContext > + { + sal_Int32 operator() () { return sal_Int32( -1 ); } + }; + +} + +//----------------------------------------------------------------------------- +struct ConfigItemListEntry_Impl +{ + ConfigItem* pConfigItem; + + ConfigItemListEntry_Impl(ConfigItem* pItem ) : + pConfigItem(pItem){} +}; +typedef std::list<ConfigItemListEntry_Impl> ConfigItemList; +struct utl::ConfigMgr_Impl +{ + ConfigItemList aItemList; +}; + +/* -----------------------------28.08.00 15:35-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigManager::ConfigManager() : + pMgrImpl(new utl::ConfigMgr_Impl) +{ + GetConfigurationProvider(); // attempt to create the provider early +} +/* -----------------------------17.11.00 13:51-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigManager::ConfigManager(Reference< XMultiServiceFactory > xConfigProv) : + xConfigurationProvider(xConfigProv), + pMgrImpl(new utl::ConfigMgr_Impl) +{ +} +/* -----------------------------28.08.00 15:35-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigManager::~ConfigManager() +{ + //check list content -> should be empty! + OSL_ENSURE(pMgrImpl->aItemList.empty(), "some ConfigItems are still alive"); + if(!pMgrImpl->aItemList.empty()) + { + ConfigItemList::iterator aListIter; + for(aListIter = pMgrImpl->aItemList.begin(); aListIter != pMgrImpl->aItemList.end(); ++aListIter) + { + ConfigItemListEntry_Impl& rEntry = *aListIter; + rEntry.pConfigItem->ReleaseConfigMgr(); + } + pMgrImpl->aItemList.erase(pMgrImpl->aItemList.begin(), pMgrImpl->aItemList.end()); + } + delete pMgrImpl; + +} +/* -----------------------------28.08.00 16:17-------------------------------- + + ---------------------------------------------------------------------------*/ +Reference< XMultiServiceFactory > ConfigManager::GetConfigurationProvider() +{ + if(!xConfigurationProvider.is()) + { + Reference< XMultiServiceFactory > xMSF = ::utl::getProcessServiceFactory(); + if ( xMSF.is() ) + { + try + { + xConfigurationProvider = Reference< XMultiServiceFactory > + (xMSF->createInstance( + C2U("com.sun.star.configuration.ConfigurationProvider")), + UNO_QUERY); + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + static sal_Bool bMessage = sal_True; + if(bMessage) + { + bMessage = sal_False; + OString sMsg("CreateInstance with arguments exception: "); + sMsg += OString(rEx.Message.getStr(), + rEx.Message.getLength(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); + } + } +#else + catch(Exception&){} +#endif + } + } + return xConfigurationProvider; +} +/* -----------------------------03.12.02 ------------------------------------- + + ---------------------------------------------------------------------------*/ +namespace +{ + // helper to achieve exception - safe registration of a ConfigItem under construction + class RegisterConfigItemHelper // : Noncopyable + { + utl::ConfigManager & rCfgMgr; + utl::ConfigItem* pCfgItem; + public: + RegisterConfigItemHelper(utl::ConfigManager & rMgr, utl::ConfigItem& rCfgItem) + : rCfgMgr(rMgr) + , pCfgItem(&rCfgItem) + { + rCfgMgr.RegisterConfigItem(rCfgItem); + } + + ~RegisterConfigItemHelper() + { + if (pCfgItem) rCfgMgr.RemoveConfigItem(*pCfgItem); + } + + void keep() { pCfgItem = 0; } + }; +} +/* -----------------------------12.12.00 17:19-------------------------------- + + ---------------------------------------------------------------------------*/ +Reference< XMultiServiceFactory > ConfigManager::GetLocalConfigurationProvider() +{ + return GetConfigurationProvider(); +} +/* -----------------------------29.08.00 12:35-------------------------------- + + ---------------------------------------------------------------------------*/ +Reference< XHierarchicalNameAccess > ConfigManager::AddConfigItem(utl::ConfigItem& rCfgItem) +{ + RegisterConfigItemHelper registeredItem(*this,rCfgItem); + Reference< XHierarchicalNameAccess > xTree = AcquireTree(rCfgItem); + registeredItem.keep(); + return xTree; +} +/* -----------------------------21.06.01 12:20-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigManager::RegisterConfigItem(utl::ConfigItem& rCfgItem) +{ + ConfigItemList::iterator aListIter = pMgrImpl->aItemList.begin(); +#ifdef DBG_UTIL + for(aListIter = pMgrImpl->aItemList.begin(); aListIter != pMgrImpl->aItemList.end(); ++aListIter) + { + ConfigItemListEntry_Impl& rEntry = *aListIter; + if(rEntry.pConfigItem == &rCfgItem) + OSL_ENSURE(sal_False, "RegisterConfigItem: already inserted!"); + } +#endif + pMgrImpl->aItemList.insert(aListIter, ConfigItemListEntry_Impl(&rCfgItem)); +} +/* -----------------------------21.06.01 12:20-------------------------------- + + ---------------------------------------------------------------------------*/ +Reference< XHierarchicalNameAccess> ConfigManager::AcquireTree(utl::ConfigItem& rCfgItem) +{ + ConfigItemList::iterator aListIter = pMgrImpl->aItemList.begin(); +#ifdef DBG_UTIL + sal_Bool bFound = sal_False; + for(aListIter = pMgrImpl->aItemList.begin(); aListIter != pMgrImpl->aItemList.end(); ++aListIter) + { + ConfigItemListEntry_Impl& rEntry = *aListIter; + if(rEntry.pConfigItem == &rCfgItem) + { + bFound = sal_True; + break; + } + } + OSL_ENSURE(bFound, "AcquireTree: ConfigItem unknown!"); +#endif + OUString sPath = C2U(cConfigBaseURL); + sPath += rCfgItem.GetSubTreeName(); + Sequence< Any > aArgs(2); + Any* pArgs = aArgs.getArray(); + PropertyValue aPath; + aPath.Name = C2U("nodepath"); + aPath.Value <<= sPath; + pArgs[0] <<= aPath; + sal_Bool bLazy = 0 != (rCfgItem.GetMode()&CONFIG_MODE_DELAYED_UPDATE); + PropertyValue aUpdate; + aUpdate.Name = C2U("lazywrite"); + aUpdate.Value.setValue(&bLazy, ::getBooleanCppuType()); + pArgs[1] <<= aUpdate; + + // Initialize item with support for reading/writing more then one locales at same time! + // It's neccessary for creation of a complete configuration entry without changing office locale + // at runtime. + if((rCfgItem.GetMode() & CONFIG_MODE_ALL_LOCALES) == CONFIG_MODE_ALL_LOCALES) + { + sal_Int32 nCount = aArgs.getLength(); + aArgs.realloc(nCount+1); + + PropertyValue aAllLocale; + aAllLocale.Name = C2U("locale"); + aAllLocale.Value <<= C2U("*" ); + aArgs[nCount] <<= aAllLocale; + } + + Reference< XMultiServiceFactory > xCfgProvider = GetConfigurationProvider(); + Reference< XInterface > xIFace; + if(xCfgProvider.is()) + { + try + { + xIFace = xCfgProvider->createInstanceWithArguments( + C2U(cAccessSrvc), + aArgs); + } + catch(Exception& rEx) + { + if (CONFIG_MODE_PROPAGATE_ERRORS & rCfgItem.GetMode()) + { + OSL_TRACE("ConfigItem: Propagating creation error: %s\n", + OUStringToOString(rEx.Message,RTL_TEXTENCODING_ASCII_US).getStr()); + + throw; + } +#ifdef DBG_UTIL + if(0 == (CONFIG_MODE_IGNORE_ERRORS & rCfgItem.GetMode())) + { + OString sMsg("CreateInstance exception: "); + sMsg += OString(rEx.Message.getStr(), + rEx.Message.getLength(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); + } +#endif + } + } + return Reference<XHierarchicalNameAccess>(xIFace, UNO_QUERY); +} +/* -----------------------------29.08.00 12:35-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigManager::RemoveConfigItem(utl::ConfigItem& rCfgItem) +{ + if( !pMgrImpl->aItemList.empty() ) + { + ConfigItemList::iterator aListIter = pMgrImpl->aItemList.begin(); + for(aListIter = pMgrImpl->aItemList.begin(); aListIter != pMgrImpl->aItemList.end(); ++aListIter) + { + ConfigItemListEntry_Impl& rEntry = *aListIter; + if(rEntry.pConfigItem == &rCfgItem) + { + pMgrImpl->aItemList.erase(aListIter); + break; + } + } + } +} +/* -----------------------------30.08.00 15:04-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigManager::StoreConfigItems() +{ + if(!pMgrImpl->aItemList.empty()) + { + ConfigItemList::iterator aListIter = pMgrImpl->aItemList.begin(); + for(aListIter = pMgrImpl->aItemList.begin(); aListIter != pMgrImpl->aItemList.end(); ++aListIter) + { + ConfigItemListEntry_Impl& rEntry = *aListIter; + if(rEntry.pConfigItem->IsModified()) + { + rEntry.pConfigItem->Commit(); + rEntry.pConfigItem->ClearModified(); + } + } + } +} +ConfigManager* ConfigManager::pConfigManager = 0; +/* -----------------------------07.09.00 11:06-------------------------------- + + ---------------------------------------------------------------------------*/ +ConfigManager* ConfigManager::GetConfigManager() +{ + if(!pConfigManager) + { + pConfigManager = new ConfigManager(); + } + return pConfigManager; +} +/* -----------------------------07.09.00 11:06-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigManager::RemoveConfigManager() +{ + if(pConfigManager) + { + delete pConfigManager; + pConfigManager = 0; + } +} +/* -----------------------------08.09.00 13:22-------------------------------- + + ---------------------------------------------------------------------------*/ +rtl::OUString ConfigManager::GetConfigBaseURL() +{ + return C2U(cConfigBaseURL); +} +/* -----------------------------25.09.00 16:34-------------------------------- + + ---------------------------------------------------------------------------*/ +Any ConfigManager::GetDirectConfigProperty(ConfigProperty eProp) +{ + switch(eProp) + { + case INSTALLPATH: + OSL_ENSURE( false, + "ConfigManager::GetDirectConfigProperty: " + "INSTALLPATH no longer supported." ); + return Any(); + case USERINSTALLURL: + OSL_ENSURE( false, + "ConfigManager::GetDirectConfigProperty: " + "USERINSTALLURL no longer supported." ); + return Any(); + case OFFICEINSTALL: + OSL_ENSURE( false, + "ConfigManager::GetDirectConfigProperty: " + "OFFICEINSTALL no longer supported." ); + return Any(); + case OFFICEINSTALLURL: + OSL_ENSURE( false, + "ConfigManager::GetDirectConfigProperty: " + "OFFICEINSTALLURL no longer supported." ); + return Any(); + default: + break; + } + + Any aRet; + ::rtl::OUString &rBrandName = BrandName::get(); + if ( eProp == PRODUCTNAME && rBrandName.getLength() ) + { + aRet <<= rBrandName; + return aRet; + } + + rtl::OUString &rProductVersion = ProductVersion::get(); + if ( eProp == PRODUCTVERSION && rProductVersion.getLength() ) + { + aRet <<= rProductVersion; + return aRet; + } + + rtl::OUString &rAboutBoxProductVersion = AboutBoxProductVersion::get(); + if ( eProp == ABOUTBOXPRODUCTVERSION && rAboutBoxProductVersion.getLength() ) + { + aRet <<= rAboutBoxProductVersion; + return aRet; + } + + rtl::OUString &rProductExtension = ProductExtension::get(); + if ( eProp == PRODUCTEXTENSION && rProductExtension.getLength() ) + { + aRet <<= rProductExtension; + return aRet; + } + + rtl::OUString &rXMLFileFormatName = XMLFileFormatName::get(); + if ( eProp == PRODUCTXMLFILEFORMATNAME && rXMLFileFormatName.getLength() ) + { + aRet <<= rXMLFileFormatName; + return aRet; + } + + rtl::OUString &rXMLFileFormatVersion = XMLFileFormatVersion::get(); + if ( eProp == PRODUCTXMLFILEFORMATVERSION && rXMLFileFormatVersion.getLength() ) + { + aRet <<= rXMLFileFormatVersion; + return aRet; + } + + sal_Int32 &rOpenSourceContext = OpenSourceContext::get(); + if ( eProp == OPENSOURCECONTEXT && ( rOpenSourceContext >= 0 ) ) + { + aRet <<= rOpenSourceContext; + return aRet; + } + + rtl::OUString &rWriterCompatibilityVersionOOo11 = WriterCompatibilityVersionOOo11::get(); + if ( eProp == WRITERCOMPATIBILITYVERSIONOOO11 && rWriterCompatibilityVersionOOo11.getLength() ) + { + aRet <<= rWriterCompatibilityVersionOOo11; + return aRet; + } + + if (eProp == PRODUCTEXTENSION) { + rtl::OUString name( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "${BRAND_BASE_DIR}/program/edition/edition.ini"))); + rtl::Bootstrap::expandMacros(name); + if (rtl::Bootstrap(name).getFrom( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EDITIONNAME")), + rProductExtension)) + { + return com::sun::star::uno::Any(rProductExtension); + } + } + + OUString sPath = C2U(cConfigBaseURL); + switch(eProp) + { + case LOCALE: sPath += C2U("Setup/L10N"); break; + + case PRODUCTNAME: + case PRODUCTVERSION: + case PRODUCTEXTENSION: + case PRODUCTXMLFILEFORMATNAME : + case PRODUCTXMLFILEFORMATVERSION: + case OPENSOURCECONTEXT: + case ABOUTBOXPRODUCTVERSION: sPath += C2U("Setup/Product"); break; + + case DEFAULTCURRENCY: sPath += C2U("Setup/L10N"); break; + + case WRITERCOMPATIBILITYVERSIONOOO11: + sPath += C2U("Office.Compatibility/WriterCompatibilityVersion"); break; + default: + break; + } + Sequence< Any > aArgs(1); + aArgs[0] <<= sPath; + Reference< XMultiServiceFactory > xCfgProvider = GetConfigManager()->GetConfigurationProvider(); + if(!xCfgProvider.is()) + return aRet; + Reference< XInterface > xIFace; + try + { + xIFace = xCfgProvider->createInstanceWithArguments( + C2U(cAccessSrvc), + aArgs); + + } + catch(Exception&){} + Reference<XNameAccess> xDirectAccess(xIFace, UNO_QUERY); + if(xDirectAccess.is()) + { + OUString sProperty; + switch(eProp) + { + case LOCALE: sProperty = C2U("ooLocale"); break; + case PRODUCTNAME: sProperty = C2U("ooName"); break; + case PRODUCTVERSION: sProperty = C2U("ooSetupVersion"); break; + case ABOUTBOXPRODUCTVERSION: sProperty = C2U("ooSetupVersionAboutBox"); break; + case PRODUCTEXTENSION: sProperty = C2U("ooSetupExtension"); break; + case PRODUCTXMLFILEFORMATNAME: sProperty = C2U("ooXMLFileFormatName"); break; + case PRODUCTXMLFILEFORMATVERSION: sProperty = C2U("ooXMLFileFormatVersion"); break; + case OPENSOURCECONTEXT: sProperty = C2U("ooOpenSourceContext"); break; + case DEFAULTCURRENCY: sProperty = C2U("ooSetupCurrency"); break; + case WRITERCOMPATIBILITYVERSIONOOO11: sProperty = C2U("OOo11"); break; + default: + break; + } + try + { + aRet = xDirectAccess->getByName(sProperty); + } + catch(Exception&) + { + #if OSL_DEBUG_LEVEL > 0 + rtl::OStringBuffer aBuf(256); + aBuf.append( "ConfigManager::GetDirectConfigProperty: could not retrieve the property \"" ); + aBuf.append( rtl::OUStringToOString( sProperty, RTL_TEXTENCODING_ASCII_US ) ); + aBuf.append( "\" under \"" ); + aBuf.append( rtl::OUStringToOString( sPath, RTL_TEXTENCODING_ASCII_US ) ); + aBuf.append( "\" (caught an exception)!" ); + OSL_ENSURE( sal_False, aBuf.getStr() ); + #endif + } + } + + if ( eProp == PRODUCTNAME ) + aRet >>= rBrandName; + + if ( eProp == PRODUCTXMLFILEFORMATNAME ) + aRet >>= rXMLFileFormatName; + + if ( eProp == PRODUCTXMLFILEFORMATVERSION ) + aRet >>= rXMLFileFormatVersion; + + if ( eProp == PRODUCTVERSION ) + aRet >>= rProductVersion; + + if ( eProp == ABOUTBOXPRODUCTVERSION ) + { + aRet >>= rAboutBoxProductVersion; + getBasisAboutBoxProductVersion( rAboutBoxProductVersion ); + aRet <<= rAboutBoxProductVersion; + } + + if ( eProp == PRODUCTEXTENSION ) + aRet >>= rProductExtension; + + if ( eProp == WRITERCOMPATIBILITYVERSIONOOO11 ) + aRet >>= rWriterCompatibilityVersionOOo11; + + if ( eProp == OPENSOURCECONTEXT ) + aRet >>= rOpenSourceContext; + + return aRet; +} + +/*---------------------------------------------------------------------------*/ +void ConfigManager::getBasisAboutBoxProductVersion( OUString& rVersion ) +{ + rtl::OUString aPackageVersion = UNISTRING( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":OOOPackageVersion}" ); + rtl::Bootstrap::expandMacros( aPackageVersion ); + + if ( aPackageVersion.getLength() ) + { + sal_Int32 nTokIndex = 0; + rtl::OUString aVersionMinor = aPackageVersion.getToken( 1, '.', nTokIndex ); + rtl::OUString aVersionMicro; + + if ( nTokIndex > 0 ) + aVersionMicro = aPackageVersion.getToken( 0, '.', nTokIndex ); + + if ( aVersionMinor.getLength() == 0 ) + aVersionMinor = UNISTRING( "0" ); + if ( aVersionMicro.getLength() == 0 ) + aVersionMicro = UNISTRING( "0" ); + + sal_Int32 nIndex = rVersion.indexOf( '.' ); + if ( nIndex == -1 ) + { + rVersion += UNISTRING( "." ); + rVersion += aVersionMinor; + } + else + { + nIndex = rVersion.indexOf( '.', nIndex+1 ); + } + if ( nIndex == -1 ) + { + rVersion += UNISTRING( "." ); + rVersion += aVersionMicro; + } + else + { + rVersion = rVersion.replaceAt( nIndex+1, rVersion.getLength()-nIndex-1, aVersionMicro ); + } + } +} + +/* -----------------------------12.12.00 17:22-------------------------------- + + ---------------------------------------------------------------------------*/ +Reference< XHierarchicalNameAccess> ConfigManager::GetHierarchyAccess(const OUString& rFullPath) +{ + Sequence< Any > aArgs(1); + aArgs[0] <<= rFullPath; + Reference< XMultiServiceFactory > xCfgProvider = GetLocalConfigurationProvider(); + Reference< XInterface > xIFace; + if(xCfgProvider.is()) + { + try + { + xIFace = xCfgProvider->createInstanceWithArguments( + C2U(cAccessSrvc), + aArgs); + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + OString sMsg("CreateInstance exception: "); + sMsg += OString(rEx.Message.getStr(), + rEx.Message.getLength(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); + } +#else + catch(Exception&){} +#endif + } + return Reference<XHierarchicalNameAccess>(xIFace, UNO_QUERY); +} +/* -----------------------------12.12.00 17:17-------------------------------- + + ---------------------------------------------------------------------------*/ +Any ConfigManager::GetLocalProperty(const OUString& rProperty) +{ + OUString sPath = C2U(cConfigBaseURL); + sPath += rProperty; + + OUString sNode, sProperty; + OSL_VERIFY( splitLastFromConfigurationPath(sPath, sNode, sProperty) ); + + Reference< XNameAccess> xAccess( GetHierarchyAccess(sNode), UNO_QUERY ); + Any aRet; + try + { + if(xAccess.is()) + aRet = xAccess->getByName(sProperty); + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + OString sMsg("GetLocalProperty: "); + sMsg += OString(rEx.Message.getStr(), + rEx.Message.getLength(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); + } +#else + catch(Exception&){} +#endif + return aRet; +} +/* -----------------------------12.12.00 17:17-------------------------------- + + ---------------------------------------------------------------------------*/ +void ConfigManager::PutLocalProperty(const OUString& rProperty, const Any& rValue) +{ + OUString sPath = C2U(cConfigBaseURL); + sPath += rProperty; + + OUString sNode, sProperty; + OSL_VERIFY( splitLastFromConfigurationPath(sPath, sNode, sProperty) ); + + Reference<XNameReplace> xNodeReplace(GetHierarchyAccess(sNode), UNO_QUERY); + if(xNodeReplace.is()) + { + try + { + xNodeReplace->replaceByName(sProperty, rValue); + } +#ifdef DBG_UTIL + catch(Exception& rEx) + { + OString sMsg("PutLocalProperty: "); + sMsg += OString(rEx.Message.getStr(), + rEx.Message.getLength(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, sMsg.getStr()); + } +#else + catch(Exception& ){} +#endif + } +} +/* -----------------------------13.12.00 08:47-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool ConfigManager::IsLocalConfigProvider() +{ + return false; +} + diff --git a/unotools/source/config/confignode.cxx b/unotools/source/config/confignode.cxx new file mode 100644 index 000000000000..4b1b9fe272db --- /dev/null +++ b/unotools/source/config/confignode.cxx @@ -0,0 +1,705 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: confignode.cxx,v $ + * $Revision: 1.12 $ + * + * 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_unotools.hxx" + +#include <unotools/confignode.hxx> +#include <unotools/configpathes.hxx> +#include <tools/diagnose_ex.h> +#include <osl/diagnose.h> +#include <com/sun/star/container/XHierarchicalName.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/util/XStringEscape.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/extract.hxx> +#include <rtl/string.hxx> +#if OSL_DEBUG_LEVEL > 0 +#include <rtl/strbuf.hxx> +#endif + +//........................................................................ +namespace utl +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + + //======================================================================== + //= OConfigurationNode + //======================================================================== + //------------------------------------------------------------------------ + OConfigurationNode::OConfigurationNode(const Reference< XInterface >& _rxNode, const Reference< XMultiServiceFactory >& _rxProvider) + :m_xProvider(_rxProvider) + ,m_bEscapeNames(sal_False) + { + OSL_ENSURE(_rxNode.is(), "OConfigurationNode::OConfigurationNode: invalid node interface!"); + if (_rxNode.is()) + { + // collect all interfaces necessary + m_xHierarchyAccess = Reference< XHierarchicalNameAccess >(_rxNode, UNO_QUERY); + m_xDirectAccess = Reference< XNameAccess >(_rxNode, UNO_QUERY); + + // reset _all_ interfaces if _one_ of them is not supported + if (!m_xHierarchyAccess.is() || !m_xDirectAccess.is()) + { + m_xHierarchyAccess = NULL; + m_xDirectAccess = NULL; + } + + // now for the non-critical interfaces + m_xReplaceAccess = Reference< XNameReplace >(_rxNode, UNO_QUERY); + m_xContainerAccess = Reference< XNameContainer >(_rxNode, UNO_QUERY); + } + + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + + if (isValid()) + setEscape(isSetNode()); + } + + //------------------------------------------------------------------------ + OConfigurationNode::OConfigurationNode(const OConfigurationNode& _rSource) + :OEventListenerAdapter() + ,m_xHierarchyAccess(_rSource.m_xHierarchyAccess) + ,m_xDirectAccess(_rSource.m_xDirectAccess) + ,m_xReplaceAccess(_rSource.m_xReplaceAccess) + ,m_xContainerAccess(_rSource.m_xContainerAccess) + ,m_xProvider(_rSource.m_xProvider) + ,m_bEscapeNames(_rSource.m_bEscapeNames) + ,m_sCompletePath(_rSource.m_sCompletePath) + { + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + } + + //------------------------------------------------------------------------ + const OConfigurationNode& OConfigurationNode::operator=(const OConfigurationNode& _rSource) + { + stopAllComponentListening(); + + m_xHierarchyAccess = _rSource.m_xHierarchyAccess; + m_xDirectAccess = _rSource.m_xDirectAccess; + m_xContainerAccess = _rSource.m_xContainerAccess; + m_xReplaceAccess = _rSource.m_xReplaceAccess; + m_xProvider = _rSource.m_xProvider; + m_bEscapeNames = _rSource.m_bEscapeNames; + m_sCompletePath = _rSource.m_sCompletePath; + + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xConfigNodeComp.is()) + startComponentListening(xConfigNodeComp); + + return *this; + } + + //------------------------------------------------------------------------ + void OConfigurationNode::_disposing( const EventObject& _rSource ) + { + Reference< XComponent > xDisposingSource(_rSource.Source, UNO_QUERY); + Reference< XComponent > xConfigNodeComp(m_xDirectAccess, UNO_QUERY); + if (xDisposingSource.get() == xConfigNodeComp.get()) + clear(); + } + + //------------------------------------------------------------------------ + ::rtl::OUString OConfigurationNode::normalizeName(const ::rtl::OUString& _rName, NAMEORIGIN _eOrigin) const + { + ::rtl::OUString sName(_rName); + if (getEscape()) + { + Reference< XStringEscape > xEscaper(m_xDirectAccess, UNO_QUERY); + OSL_ENSURE(xEscaper.is(), "OConfigurationNode::normalizeName: missing an interface!"); + if (xEscaper.is() && sName.getLength()) + { + try + { + if (NO_CALLER == _eOrigin) + sName = xEscaper->escapeString(sName); + else + sName = xEscaper->unescapeString(sName); + } + catch(IllegalArgumentException&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::normalizeName: illegal argument (caught an exception saying so)!"); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::normalizeName: caught an exception!"); + } + } + } + return sName; + } + + //------------------------------------------------------------------------ + Sequence< ::rtl::OUString > OConfigurationNode::getNodeNames() const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::getNodeNames: object is invalid!"); + Sequence< ::rtl::OUString > aReturn; + if (m_xDirectAccess.is()) + { + try + { + aReturn = m_xDirectAccess->getElementNames(); + // normalize the names + ::rtl::OUString* pNames = aReturn.getArray(); + for (sal_Int32 i=0; i<aReturn.getLength(); ++i, ++pNames) + *pNames = normalizeName(*pNames, NO_CONFIGURATION); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::getNodeNames: caught a generic exception!"); + } + } + + return aReturn; + } + + //------------------------------------------------------------------------ + sal_Bool OConfigurationNode::removeNode(const ::rtl::OUString& _rName) const throw() + { + OSL_ENSURE(m_xContainerAccess.is(), "OConfigurationNode::removeNode: object is invalid!"); + if (m_xContainerAccess.is()) + { + try + { + ::rtl::OUString sName = normalizeName(_rName, NO_CALLER); + m_xContainerAccess->removeByName(sName); + return sal_True; + } + catch (NoSuchElementException&) + { + #if OSL_DEBUG_LEVEL > 0 + rtl::OStringBuffer aBuf( 256 ); + aBuf.append("OConfigurationNode::removeNode: there is no element named!"); + aBuf.append( rtl::OUStringToOString( _rName, RTL_TEXTENCODING_ASCII_US ) ); + aBuf.append( "!" ); + OSL_ENSURE(sal_False, aBuf.getStr()); + #endif + } + catch (WrappedTargetException&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::removeNode: caught a WrappedTargetException!"); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::removeNode: caught a generic exception!"); + } + } + return sal_False; + } + //------------------------------------------------------------------------ + OConfigurationNode OConfigurationNode::insertNode(const ::rtl::OUString& _rName,const Reference< XInterface >& _xNode) const throw() + { + if(_xNode.is()) + { + try + { + ::rtl::OUString sName = normalizeName(_rName, NO_CALLER); + m_xContainerAccess->insertByName(sName, makeAny(_xNode)); + // if we're here, all was ok ... + return OConfigurationNode(_xNode, m_xProvider); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // dispose the child if it has already been created, but could not be inserted + Reference< XComponent > xChildComp(_xNode, UNO_QUERY); + if (xChildComp.is()) + try { xChildComp->dispose(); } catch(Exception&) { } + } + + return OConfigurationNode(); + } + //------------------------------------------------------------------------ + OConfigurationNode OConfigurationNode::createNode(const ::rtl::OUString& _rName) const throw() + { + Reference< XSingleServiceFactory > xChildFactory(m_xContainerAccess, UNO_QUERY); + OSL_ENSURE(xChildFactory.is(), "OConfigurationNode::createNode: object is invalid or read-only!"); + + if (xChildFactory.is()) // implies m_xContainerAccess.is() + { + Reference< XInterface > xNewChild; + try + { + xNewChild = xChildFactory->createInstance(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + return insertNode(_rName,xNewChild); + } + + return OConfigurationNode(); + } + + //------------------------------------------------------------------------ + OConfigurationNode OConfigurationNode::appendNode(const ::rtl::OUString& _rName,const OConfigurationNode& _aNewNode) const throw() + { + return insertNode(_rName,_aNewNode.m_xDirectAccess); + } + //------------------------------------------------------------------------ + OConfigurationNode OConfigurationNode::openNode(const ::rtl::OUString& _rPath) const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::openNode: object is invalid!"); + OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::openNode: object is invalid!"); + try + { + ::rtl::OUString sNormalized = normalizeName(_rPath, NO_CALLER); + + Reference< XInterface > xNode; + if (m_xDirectAccess.is() && m_xDirectAccess->hasByName(sNormalized)) + { + if (!::cppu::extractInterface(xNode, m_xDirectAccess->getByName(sNormalized))) + OSL_ENSURE(sal_False, "OConfigurationNode::openNode: could not open the node!"); + } + else if (m_xHierarchyAccess.is()) + { + if (!::cppu::extractInterface(xNode, m_xHierarchyAccess->getByHierarchicalName(_rPath))) + OSL_ENSURE(sal_False, "OConfigurationNode::openNode: could not open the node!"); + } + if (xNode.is()) + return OConfigurationNode(xNode, m_xProvider); + } + catch(NoSuchElementException& e) + { + (void)e; + #if OSL_DEBUG_LEVEL > 0 + rtl::OStringBuffer aBuf( 256 ); + aBuf.append("OConfigurationNode::openNode: there is no element named "); + aBuf.append( rtl::OUStringToOString( _rPath, RTL_TEXTENCODING_ASCII_US ) ); + aBuf.append("!"); + OSL_ENSURE(sal_False, aBuf.getStr()); + #endif + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::openNode: caught an exception while retrieving the node!"); + } + return OConfigurationNode(); + } + + //------------------------------------------------------------------------ + void OConfigurationNode::setEscape(sal_Bool _bEnable) + { + m_bEscapeNames = _bEnable && Reference< XStringEscape >::query(m_xDirectAccess).is(); + OSL_ENSURE(m_bEscapeNames || !_bEnable, + "OConfigurationNode::setEscape: escaping not enabled - missing the appropriate interface on the node!"); + } + + //------------------------------------------------------------------------ + sal_Bool OConfigurationNode::isSetNode() const + { + sal_Bool bIsSet = sal_False; + Reference< XServiceInfo > xSI(m_xHierarchyAccess, UNO_QUERY); + if (xSI.is()) + { + try { bIsSet = xSI->supportsService(::rtl::OUString::createFromAscii("com.sun.star.configuration.SetAccess")); } + catch(Exception&) { } + } + return bIsSet; + } + + //--------------------------------------------------------------------- + //--- 20.08.01 19:03:20 ----------------------------------------------- + + sal_Bool OConfigurationNode::hasByHierarchicalName( const ::rtl::OUString& _rName ) const throw() + { + OSL_ENSURE( m_xHierarchyAccess.is(), "OConfigurationNode::hasByHierarchicalName: no hierarchy access!" ); + try + { + if ( m_xHierarchyAccess.is() ) + { + ::rtl::OUString sName = normalizeName( _rName, NO_CALLER ); + return m_xHierarchyAccess->hasByHierarchicalName( sName ); + } + } + catch(Exception&) + { + } + return sal_False; + } + + //------------------------------------------------------------------------ + sal_Bool OConfigurationNode::hasByName(const ::rtl::OUString& _rName) const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::hasByName: object is invalid!"); + try + { + ::rtl::OUString sName = normalizeName(_rName, NO_CALLER); + if (m_xDirectAccess.is()) + return m_xDirectAccess->hasByName(sName); + } + catch(Exception&) + { + } + return sal_False; + } + + //------------------------------------------------------------------------ + sal_Bool OConfigurationNode::setNodeValue(const ::rtl::OUString& _rPath, const Any& _rValue) const throw() + { + sal_Bool bResult = false; + + OSL_ENSURE(m_xReplaceAccess.is(), "OConfigurationNode::setNodeValue: object is invalid!"); + if (m_xReplaceAccess.is()) + { + try + { + // check if _rPath is a level-1 path + ::rtl::OUString sNormalizedName = normalizeName(_rPath, NO_CALLER); + if (m_xReplaceAccess->hasByName(sNormalizedName)) + { + m_xReplaceAccess->replaceByName(sNormalizedName, _rValue); + bResult = true; + } + + // check if the name refers to a indirect descendant + else if (m_xHierarchyAccess.is() && m_xHierarchyAccess->hasByHierarchicalName(_rPath)) + { + OSL_ASSERT(_rPath.getLength()); + + ::rtl::OUString sParentPath, sLocalName; + + if ( splitLastFromConfigurationPath(_rPath, sParentPath, sLocalName) ) + { + OConfigurationNode aParentAccess = openNode(sParentPath); + if (aParentAccess.isValid()) + bResult = aParentAccess.setNodeValue(sLocalName, _rValue); + } + else + { + m_xReplaceAccess->replaceByName(sLocalName, _rValue); + bResult = true; + } + } + + } + catch(IllegalArgumentException&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::setNodeValue: could not replace the value: caught an IllegalArgumentException!"); + } + catch(NoSuchElementException&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::setNodeValue: could not replace the value: caught a NoSuchElementException!"); + } + catch(WrappedTargetException&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::setNodeValue: could not replace the value: caught a WrappedTargetException!"); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::setNodeValue: could not replace the value: caught a generic Exception!"); + } + + + } + return bResult; + } + + //------------------------------------------------------------------------ + Any OConfigurationNode::getNodeValue(const ::rtl::OUString& _rPath) const throw() + { + OSL_ENSURE(m_xDirectAccess.is(), "OConfigurationNode::hasByName: object is invalid!"); + OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::hasByName: object is invalid!"); + Any aReturn; + try + { + ::rtl::OUString sNormalizedPath = normalizeName(_rPath, NO_CALLER); + if (m_xDirectAccess.is() && m_xDirectAccess->hasByName(sNormalizedPath) ) + { + aReturn = m_xDirectAccess->getByName(sNormalizedPath); + } + else if (m_xHierarchyAccess.is()) + { + aReturn = m_xHierarchyAccess->getByHierarchicalName(_rPath); + } + } + catch(NoSuchElementException& e) + { + #if OSL_DEBUG_LEVEL > 0 + rtl::OStringBuffer aBuf( 256 ); + aBuf.append("OConfigurationNode::getNodeValue: caught a NoSuchElementException while trying to open "); + aBuf.append( rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ) ); + OSL_ENSURE(sal_False, aBuf.getStr()); + #else + (void)e; + #endif + } + return aReturn; + } + + //------------------------------------------------------------------------ + OConfigurationTreeRoot OConfigurationNode::cloneAsRoot() const throw() + { + OSL_ENSURE(m_xHierarchyAccess.is(), "OConfigurationNode::cloneAsRoot: object is invalid!"); + if (m_xHierarchyAccess.is()) + { + // first get the complete path of the node we represent + ::rtl::OUString sCompletePath; + Reference< XHierarchicalName > xNodeNameAccess(m_xHierarchyAccess, UNO_QUERY); + if (xNodeNameAccess.is()) + { + try + { + sCompletePath = xNodeNameAccess->getHierarchicalName(); + OSL_ENSURE(sCompletePath.getLength(), "OConfigurationNode::cloneAsRoot: invalid path retrieved!"); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationNode::cloneAsRoot: could not retrieve the node path!"); + } + } + + // then create a new tree root object with that path and our provider + OSL_ENSURE(m_xProvider.is(), "OConfigurationNode::cloneAsRoot: have an invalid provider!"); + if (sCompletePath.getLength() && m_xProvider.is()) + { + return OConfigurationTreeRoot::createWithProvider(m_xProvider, sCompletePath, -1, isReadonly() ? OConfigurationTreeRoot::CM_READONLY : OConfigurationTreeRoot::CM_PREFER_UPDATABLE); + } + } + return OConfigurationTreeRoot(); + } + + //------------------------------------------------------------------------ + void OConfigurationNode::clear() throw() + { + m_xHierarchyAccess.clear(); + m_xDirectAccess.clear(); + m_xReplaceAccess.clear(); + m_xContainerAccess.clear(); + } + + //======================================================================== + //= OConfigurationTreeRoot + //======================================================================== + //------------------------------------------------------------------------ + OConfigurationTreeRoot::OConfigurationTreeRoot(const Reference< XChangesBatch >& _rxRootNode, const Reference< XMultiServiceFactory >& _rxProvider) + :OConfigurationNode(_rxRootNode.get(), _rxProvider) + ,m_xCommitter(_rxRootNode) + { + } + + //------------------------------------------------------------------------ + OConfigurationTreeRoot::OConfigurationTreeRoot(const Reference< XInterface >& _rxRootNode, const Reference< XMultiServiceFactory >& _rxProvider) + :OConfigurationNode(_rxRootNode.get(), _rxProvider) + { + } + + //------------------------------------------------------------------------ + void OConfigurationTreeRoot::clear() throw() + { + OConfigurationNode::clear(); + m_xCommitter.clear(); + } + + //------------------------------------------------------------------------ + sal_Bool OConfigurationTreeRoot::commit() const throw() + { + OSL_ENSURE(isValid(), "OConfigurationTreeRoot::commit: object is invalid!"); + if (!isValid()) + return sal_False; + OSL_ENSURE(m_xCommitter.is(), "OConfigurationTreeRoot::commit: I'm a readonly node!"); + if (!m_xCommitter.is()) + return sal_False; + + try + { + m_xCommitter->commitChanges(); + return sal_True; + } + catch(WrappedTargetException&) + { + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::commit: caught a WrappedTargetException!"); + } + catch(RuntimeException&) + { + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::commit: caught a RuntimeException!"); + } + return sal_False; + } + + namespace + { + static const ::rtl::OUString& lcl_getProviderServiceName( ) + { + static ::rtl::OUString s_sProviderServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) ); + return s_sProviderServiceName; + } + } + + //------------------------------------------------------------------------ + OConfigurationTreeRoot OConfigurationTreeRoot::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider, const ::rtl::OUString& _rPath, sal_Int32 _nDepth, CREATION_MODE _eMode, sal_Bool _bLazyWrite) + { + OSL_ENSURE(_rxConfProvider.is(), "OConfigurationTreeRoot::createWithProvider: invalid provider!"); + +#ifdef DBG_UTIL + if (_rxConfProvider.is()) + { + try + { + Reference< XServiceInfo > xSI(_rxConfProvider, UNO_QUERY); + if (!xSI.is()) + { + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::createWithProvider: no XServiceInfo interface on the provider!"); + } + else + { + OSL_ENSURE(xSI->supportsService( lcl_getProviderServiceName( ) ), + "OConfigurationTreeRoot::createWithProvider: sure this is a provider? Missing the ConfigurationProvider service!"); + } + } + catch(const Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::createWithProvider: unable to check the service conformance of the provider given!"); + } + } +#endif + + sal_Bool bTryAgain(sal_False); + do + { + if (_rxConfProvider.is()) + { + try + { + Sequence< Any > aCreationArgs(3); + aCreationArgs[0] = makeAny(PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("nodepath")), 0, makeAny(_rPath), PropertyState_DIRECT_VALUE)); + aCreationArgs[1] = makeAny(PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("depth")), 0, makeAny((sal_Int32)_nDepth), PropertyState_DIRECT_VALUE)); + aCreationArgs[2] = makeAny(PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("lazywrite")), 0, ::cppu::bool2any(_bLazyWrite), PropertyState_DIRECT_VALUE)); + + ::rtl::OUString sAccessService = ::rtl::OUString::createFromAscii(CM_READONLY == _eMode + ? "com.sun.star.configuration.ConfigurationAccess" + : "com.sun.star.configuration.ConfigurationUpdateAccess"); + + Reference< XInterface > xRoot = _rxConfProvider->createInstanceWithArguments(sAccessService, aCreationArgs); + if (!xRoot.is()) + { + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::createWithProvider: could not create the node access!"); + } + else if (CM_READONLY == _eMode) + { + return OConfigurationTreeRoot(xRoot, _rxConfProvider); + } + else + { // get the changes batch interface + Reference< XChangesBatch > xCommitter(xRoot, UNO_QUERY); + if (xCommitter.is()) + return OConfigurationTreeRoot(xCommitter, _rxConfProvider); + else + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::createWithProvider: invalid root object (missing interface XChangesBatch)!"); + + // dispose the object if it is already created, but unusable + Reference< XComponent > xComp(xRoot, UNO_QUERY); + if (xComp.is()) + try { xComp->dispose(); } catch(Exception&) { } + } + } + catch(Exception& e) + { + #if OSL_DEBUG_LEVEL > 0 + ::rtl::OString sMessage( "OConfigurationTreeRoot::createWithProvider: caught an exception while creating the access object!\nmessage:\n" ); + sMessage += ::rtl::OString( e.Message.getStr(), e.Message.getLength(), RTL_TEXTENCODING_ASCII_US ); + OSL_ENSURE( sal_False, sMessage.getStr() ); + #else + (void)e; + #endif + } + } + bTryAgain = CM_PREFER_UPDATABLE == _eMode; + if (bTryAgain) + _eMode = CM_READONLY; + } + while (bTryAgain); + + return OConfigurationTreeRoot(); + } + + //------------------------------------------------------------------------ + OConfigurationTreeRoot OConfigurationTreeRoot::createWithServiceFactory(const Reference< XMultiServiceFactory >& _rxORB, const ::rtl::OUString& _rPath, sal_Int32 _nDepth, CREATION_MODE _eMode, sal_Bool _bLazyWrite) + { + OSL_ENSURE(_rxORB.is(), "OConfigurationTreeRoot::createWithServiceFactory: invalid service factory!"); + if (_rxORB.is()) + { + try + { + Reference< XInterface > xProvider = _rxORB->createInstance( lcl_getProviderServiceName( ) ); + OSL_ENSURE(xProvider.is(), "OConfigurationTreeRoot::createWithServiceFactory: could not instantiate the config provider service!"); + Reference< XMultiServiceFactory > xProviderAsFac(xProvider, UNO_QUERY); + OSL_ENSURE(xProviderAsFac.is() || !xProvider.is(), "OConfigurationTreeRoot::createWithServiceFactory: the provider is missing an interface!"); + if (xProviderAsFac.is()) + return createWithProvider(xProviderAsFac, _rPath, _nDepth, _eMode, _bLazyWrite); + } + catch(Exception&) + { + OSL_ENSURE(sal_False, "OConfigurationTreeRoot::createWithServiceFactory: error while instantiating the provider service!"); + } + } + return OConfigurationTreeRoot(); + } + + //------------------------------------------------------------------------ + OConfigurationTreeRoot OConfigurationTreeRoot::tryCreateWithServiceFactory( const Reference< XMultiServiceFactory >& _rxORB, + const ::rtl::OUString& _rPath, sal_Int32 _nDepth , CREATION_MODE _eMode , sal_Bool _bLazyWrite ) + { + OSL_ENSURE( _rxORB.is(), "OConfigurationTreeRoot::tryCreateWithServiceFactory: invalid service factory!" ); + if ( _rxORB.is() ) + { + try + { + Reference< XMultiServiceFactory > xConfigFactory( _rxORB->createInstance( lcl_getProviderServiceName( ) ), UNO_QUERY ); + if ( xConfigFactory.is() ) + return createWithProvider( xConfigFactory, _rPath, _nDepth, _eMode, _bLazyWrite ); + } + catch(Exception&) + { + // silent this, 'cause the contract of this method states "no assertions" + } + } + return OConfigurationTreeRoot(); + } + +//........................................................................ +} // namespace utl +//........................................................................ + diff --git a/unotools/source/config/configpathes.cxx b/unotools/source/config/configpathes.cxx new file mode 100644 index 000000000000..3e90823a7975 --- /dev/null +++ b/unotools/source/config/configpathes.cxx @@ -0,0 +1,306 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: configpathes.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" + +#include "unotools/configpathes.hxx" +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/diagnose.h> + +//---------------------------------------------------------------------------- +namespace utl +{ +//---------------------------------------------------------------------------- + + using ::rtl::OUString; + using ::rtl::OUStringBuffer; + +//---------------------------------------------------------------------------- + +static +void lcl_resolveCharEntities(OUString & aLocalString) +{ + sal_Int32 nEscapePos=aLocalString.indexOf('&'); + if (nEscapePos < 0) return; + + OUStringBuffer aResult; + sal_Int32 nStart = 0; + + do + { + sal_Unicode ch = 0; + if (aLocalString.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("&"),nEscapePos)) + ch = '&'; + + else if (aLocalString.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("'"),nEscapePos)) + ch = '\''; + + else if (aLocalString.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("""),nEscapePos)) + ch = '"'; + + OSL_ENSURE(ch,"Configuration path contains '&' that is not part of a valid character escape"); + if (ch) + { + aResult.append(aLocalString.copy(nStart,nEscapePos-nStart)).append(ch); + + sal_Int32 nEscapeEnd=aLocalString.indexOf(';',nEscapePos); + nStart = nEscapeEnd+1; + nEscapePos=aLocalString.indexOf('&',nStart); + } + else + { + nEscapePos=aLocalString.indexOf('&',nEscapePos+1); + } + } + while ( nEscapePos > 0); + + aResult.append(aLocalString.copy(nStart)); + + aLocalString = aResult.makeStringAndClear(); +} + +//---------------------------------------------------------------------------- +sal_Bool splitLastFromConfigurationPath(OUString const& _sInPath, + OUString& _rsOutPath, + OUString& _rsLocalName) +{ + sal_Int32 nStart,nEnd; + + sal_Int32 nPos = _sInPath.getLength()-1; + + // strip trailing slash + if (nPos > 0 && _sInPath[ nPos ] == sal_Unicode('/')) + { + OSL_ENSURE(false, "Invalid config path: trailing '/' is not allowed"); + --nPos; + } + + // check for predicate ['xxx'] or ["yyy"] + if (nPos > 0 && _sInPath[ nPos ] == sal_Unicode(']')) + { + sal_Unicode chQuote = _sInPath[--nPos]; + + if (chQuote == '\'' || chQuote == '\"') + { + nEnd = nPos; + nPos = _sInPath.lastIndexOf(chQuote,nEnd); + nStart = nPos + 1; + --nPos; // nPos = rInPath.lastIndexOf('[',nPos); + } + else // allow [xxx] + { + nEnd = nPos + 1; + nPos = _sInPath.lastIndexOf('[',nEnd); + nStart = nPos + 1; + } + + OSL_ENSURE(nPos >= 0 && _sInPath[nPos] == '[', "Invalid config path: unmatched quotes or brackets"); + if (nPos >= 0 && _sInPath[nPos] == '[') + { + nPos = _sInPath.lastIndexOf('/',nPos); + } + else // defined behavior for invalid pathes + { + nStart = 0, nEnd = _sInPath.getLength(); + nPos = -1; + } + + } + else + { + nEnd = nPos+1; + nPos = _sInPath.lastIndexOf('/',nEnd); + nStart = nPos + 1; + } + OSL_ASSERT( -1 <= nPos && + nPos < nStart && + nStart < nEnd && + nEnd <= _sInPath.getLength() ); + + OSL_ASSERT(nPos == -1 || _sInPath[nPos] == '/'); + OSL_ENSURE(nPos != 0 , "Invalid config child path: immediate child of root"); + + _rsLocalName = _sInPath.copy(nStart, nEnd-nStart); + _rsOutPath = (nPos > 0) ? _sInPath.copy(0,nPos) : OUString(); + lcl_resolveCharEntities(_rsLocalName); + + return nPos >= 0; +} + +//---------------------------------------------------------------------------- +OUString extractFirstFromConfigurationPath(OUString const& _sInPath) +{ + sal_Int32 nSep = _sInPath.indexOf('/'); + sal_Int32 nBracket = _sInPath.indexOf('['); + + sal_Int32 nStart = nBracket + 1; + sal_Int32 nEnd = nSep; + + if (0 <= nBracket) // found a bracket-quoted relative path + { + if (nSep < 0 || nBracket < nSep) // and the separator comes after it + { + sal_Unicode chQuote = _sInPath[nStart]; + if (chQuote == '\'' || chQuote == '\"') + { + ++nStart; + nEnd = _sInPath.indexOf(chQuote, nStart+1); + nBracket = nEnd+1; + } + else + { + nEnd = _sInPath.indexOf(']',nStart); + nBracket = nEnd; + } + OSL_ENSURE(nEnd > nStart && _sInPath[nBracket] == ']', "Invalid config path: improper mismatch of quote or bracket"); + OSL_DEBUG_ONLY(nSep = nBracket+1); + OSL_ENSURE(nSep == _sInPath.getLength() || _sInPath[nSep] == '/', "Invalid config path: brackets not followed by slash"); + } + else // ... but our initial element name is in simple form + nStart = 0; + } + + OUString sResult = (nEnd >= 0) ? _sInPath.copy(nStart, nEnd-nStart) : _sInPath; + lcl_resolveCharEntities(sResult); + return sResult; +} + +//---------------------------------------------------------------------------- + +// find the position after the prefix in the nested path +static inline +sal_Int32 lcl_findPrefixEnd(OUString const& _sNestedPath, OUString const& _sPrefixPath) +{ + // TODO: currently handles only exact prefix matches + sal_Int32 nPrefixLength = _sPrefixPath.getLength(); + + OSL_ENSURE(nPrefixLength == 0 || _sPrefixPath[nPrefixLength-1] != '/', + "Cannot handle slash-terminated prefix pathes"); + + sal_Bool bIsPrefix; + if (_sNestedPath.getLength() > nPrefixLength) + { + bIsPrefix = _sNestedPath[nPrefixLength] == '/' && + _sNestedPath.compareTo(_sPrefixPath,nPrefixLength) == 0; + ++nPrefixLength; + } + else if (_sNestedPath.getLength() == nPrefixLength) + { + bIsPrefix = _sNestedPath.equals(_sPrefixPath); + } + else + { + bIsPrefix = false; + } + + return bIsPrefix ? nPrefixLength : 0; +} + +//---------------------------------------------------------------------------- +sal_Bool isPrefixOfConfigurationPath(OUString const& _sNestedPath, + OUString const& _sPrefixPath) +{ + return _sPrefixPath.getLength() == 0 || lcl_findPrefixEnd(_sNestedPath,_sPrefixPath) != 0; +} + +//---------------------------------------------------------------------------- +OUString dropPrefixFromConfigurationPath(OUString const& _sNestedPath, + OUString const& _sPrefixPath) +{ + if ( sal_Int32 nPrefixEnd = lcl_findPrefixEnd(_sNestedPath,_sPrefixPath) ) + { + return _sNestedPath.copy(nPrefixEnd); + } + else + { + OSL_ENSURE(_sPrefixPath.getLength() == 0, "Path does not start with expected prefix"); + + return _sNestedPath; + } +} + +//---------------------------------------------------------------------------- +static +OUString lcl_wrapName(const OUString& _sContent, const OUString& _sType) +{ + const sal_Unicode * const pBeginContent = _sContent.getStr(); + const sal_Unicode * const pEndContent = pBeginContent + _sContent.getLength(); + + OSL_PRECOND(_sType.getLength(), "Unexpected config type name: empty"); + OSL_PRECOND(pBeginContent <= pEndContent, "Invalid config name: empty"); + + if (pBeginContent == pEndContent) + return _sType; + + rtl::OUStringBuffer aNormalized(_sType.getLength() + _sContent.getLength() + 4); // reserve approximate size initially + + // prefix: type, opening bracket and quote + aNormalized.append( _sType ).appendAscii( RTL_CONSTASCII_STRINGPARAM("['") ); + + // content: copy over each char and handle escaping + for(const sal_Unicode* pCur = pBeginContent; pCur != pEndContent; ++pCur) + { + // append (escape if needed) + switch(*pCur) + { + case sal_Unicode('&') : aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") ); break; + case sal_Unicode('\''): aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") ); break; + case sal_Unicode('\"'): aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") ); break; + + default: aNormalized.append( *pCur ); + } + } + + // suffix: closing quote and bracket + aNormalized.appendAscii( RTL_CONSTASCII_STRINGPARAM("']") ); + + return aNormalized.makeStringAndClear(); +} + +//---------------------------------------------------------------------------- + +OUString wrapConfigurationElementName(OUString const& _sElementName) +{ + return lcl_wrapName(_sElementName, OUString(RTL_CONSTASCII_USTRINGPARAM("*")) ); +} + +//---------------------------------------------------------------------------- + +OUString wrapConfigurationElementName(OUString const& _sElementName, + OUString const& _sTypeName) +{ + // todo: check that _sTypeName is valid + return lcl_wrapName(_sElementName, _sTypeName); +} + +//---------------------------------------------------------------------------- +} // namespace utl diff --git a/unotools/source/config/configvaluecontainer.cxx b/unotools/source/config/configvaluecontainer.cxx new file mode 100644 index 000000000000..6c7962cc09c1 --- /dev/null +++ b/unotools/source/config/configvaluecontainer.cxx @@ -0,0 +1,459 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: configvaluecontainer.cxx,v $ + * $Revision: 1.9 $ + * + * 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_unotools.hxx" +#include <unotools/configvaluecontainer.hxx> +#include <unotools/confignode.hxx> +#include <tools/debug.hxx> +#include <comphelper/stl_types.hxx> +#include <uno/data.h> +#include <algorithm> + +#ifdef DBG_UTIL +#include <rtl/strbuf.hxx> +#endif + +//......................................................................... +namespace utl +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //===================================================================== + //= NodeValueAccessor + //===================================================================== + enum LocationType + { + ltSimplyObjectInstance, + ltAnyInstance, + + ltUnbound + }; + + struct NodeValueAccessor + { + private: + ::rtl::OUString sRelativePath; // the relative path of the node + LocationType eLocationType; // the type of location where the value is stored + void* pLocation; // the pointer to the location + Type aDataType; // the type object pointed to by pLocation + + public: + NodeValueAccessor( const ::rtl::OUString& _rNodePath ); + + void bind( void* _pLocation, const Type& _rType ); + void bind( Any* _pLocation ); + + bool isBound( ) const { return ( ltUnbound != eLocationType ) && ( NULL != pLocation ); } + const ::rtl::OUString& getPath( ) const { return sRelativePath; } + LocationType getLocType( ) const { return eLocationType; } + void* getLocation( ) const { return pLocation; } + const Type& getDataType( ) const { return aDataType; } + + bool operator == ( const NodeValueAccessor& rhs ) const; + bool operator != ( const NodeValueAccessor& rhs ) const { return !operator == ( rhs ); } + }; + + //--------------------------------------------------------------------- + //--- 20.08.01 17:21:13 ----------------------------------------------- + + NodeValueAccessor::NodeValueAccessor( const ::rtl::OUString& _rNodePath ) + :sRelativePath( _rNodePath ) + ,eLocationType( ltUnbound ) + ,pLocation( NULL ) + { + } + + //--------------------------------------------------------------------- + //--- 20.08.01 17:06:36 ----------------------------------------------- + + bool NodeValueAccessor::operator == ( const NodeValueAccessor& rhs ) const + { + return ( sRelativePath == rhs.sRelativePath ) + && ( eLocationType == rhs.eLocationType ) + && ( pLocation == rhs.pLocation ); + } + + //--------------------------------------------------------------------- + //--- 20.08.01 17:47:43 ----------------------------------------------- + + void NodeValueAccessor::bind( void* _pLocation, const Type& _rType ) + { + DBG_ASSERT( !isBound(), "NodeValueAccessor::bind: already bound!" ); + + eLocationType = ltSimplyObjectInstance; + pLocation = _pLocation; + aDataType = _rType; + } + + //--------------------------------------------------------------------- + //--- 20.08.01 17:48:47 ----------------------------------------------- + + void NodeValueAccessor::bind( Any* _pLocation ) + { + DBG_ASSERT( !isBound(), "NodeValueAccessor::bind: already bound!" ); + + eLocationType = ltAnyInstance; + pLocation = _pLocation; + aDataType = ::getCppuType( _pLocation ); + } + + //--------------------------------------------------------------------- + //--- 20.08.01 17:42:17 ----------------------------------------------- + + #ifndef UNX + static + #endif + void lcl_copyData( const NodeValueAccessor& _rAccessor, const Any& _rData, ::osl::Mutex& _rMutex ) + { + ::osl::MutexGuard aGuard( _rMutex ); + + DBG_ASSERT( _rAccessor.isBound(), "::utl::lcl_copyData: invalid accessor!" ); + switch ( _rAccessor.getLocType() ) + { + case ltSimplyObjectInstance: + { + if ( _rData.hasValue() ) + { +#ifdef DBG_UTIL + sal_Bool bSuccess = +#endif + // assign the value + uno_type_assignData( + _rAccessor.getLocation(), _rAccessor.getDataType().getTypeLibType(), + const_cast< void* >( _rData.getValue() ), _rData.getValueType().getTypeLibType(), + (uno_QueryInterfaceFunc)cpp_queryInterface, (uno_AcquireFunc)cpp_acquire, (uno_ReleaseFunc)cpp_release + ); + #ifdef DBG_UTIL + rtl::OStringBuffer aBuf( 256 ); + aBuf.append("::utl::lcl_copyData( Accessor, Any ): could not assign the data (node path: "); + aBuf.append( rtl::OUStringToOString( _rAccessor.getPath(), RTL_TEXTENCODING_ASCII_US ) ); + aBuf.append( " !" ); + DBG_ASSERT( bSuccess, aBuf.getStr() ); + #endif + } + else { + DBG_WARNING( "::utl::lcl_copyData: NULL value lost!" ); + } + } + break; + case ltAnyInstance: + // a simple assignment of an Any ... + *static_cast< Any* >( _rAccessor.getLocation() ) = _rData; + break; + default: + break; + } + } + + //--------------------------------------------------------------------- + //--- 21.08.01 12:06:43 ----------------------------------------------- + + #ifndef UNX + static + #endif + void lcl_copyData( Any& _rData, const NodeValueAccessor& _rAccessor, ::osl::Mutex& _rMutex ) + { + ::osl::MutexGuard aGuard( _rMutex ); + + DBG_ASSERT( _rAccessor.isBound(), "::utl::lcl_copyData: invalid accessor!" ); + switch ( _rAccessor.getLocType() ) + { + case ltSimplyObjectInstance: + // a simple setValue .... + _rData.setValue( _rAccessor.getLocation(), _rAccessor.getDataType() ); + break; + + case ltAnyInstance: + // a simple assignment of an Any ... + _rData = *static_cast< Any* >( _rAccessor.getLocation() ); + break; + default: + break; + } + } + + //===================================================================== + //= functors on NodeValueAccessor instances + //===================================================================== + + //--------------------------------------------------------------------- + //--- 21.08.01 12:01:16 ----------------------------------------------- + + /// base class for functors syncronizing between exchange locations and config sub nodes + struct SubNodeAccess : public ::std::unary_function< NodeValueAccessor, void > + { + protected: + const OConfigurationNode& m_rRootNode; + ::osl::Mutex& m_rMutex; + + public: + SubNodeAccess( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) + :m_rRootNode( _rRootNode ) + ,m_rMutex( _rMutex ) + { + } + }; + + //--------------------------------------------------------------------- + //--- 21.08.01 11:25:56 ----------------------------------------------- + + struct UpdateFromConfig : public SubNodeAccess + { + public: + UpdateFromConfig( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) : SubNodeAccess( _rRootNode, _rMutex ) { } + + void operator() ( NodeValueAccessor& _rAccessor ) + { + ::utl::lcl_copyData( _rAccessor, m_rRootNode.getNodeValue( _rAccessor.getPath( ) ), m_rMutex ); + } + }; + + //--------------------------------------------------------------------- + //--- 21.08.01 11:25:56 ----------------------------------------------- + + struct UpdateToConfig : public SubNodeAccess + { + public: + UpdateToConfig( const OConfigurationNode& _rRootNode, ::osl::Mutex& _rMutex ) : SubNodeAccess( _rRootNode, _rMutex ) { } + + void operator() ( NodeValueAccessor& _rAccessor ) + { + Any aNewValue; + lcl_copyData( aNewValue, _rAccessor, m_rMutex ); + m_rRootNode.setNodeValue( _rAccessor.getPath( ), aNewValue ); + } + }; + + //--------------------------------------------------------------------- + //--- 20.08.01 16:58:24 ----------------------------------------------- + + DECLARE_STL_VECTOR( NodeValueAccessor, NodeValueAccessors ); + + //===================================================================== + //= OConfigurationValueContainerImpl + //===================================================================== + struct OConfigurationValueContainerImpl + { + Reference< XMultiServiceFactory > xORB; // the service factory + ::osl::Mutex& rMutex; // the mutex for accessing the data containers + OConfigurationTreeRoot aConfigRoot; // the configuration node we're accessing + + NodeValueAccessors aAccessors; // the accessors to the node values + + OConfigurationValueContainerImpl( const Reference< XMultiServiceFactory >& _rxORB, ::osl::Mutex& _rMutex ) + :xORB( _rxORB ) + ,rMutex( _rMutex ) + { + } + }; + + //===================================================================== + //= OConfigurationValueContainer + //===================================================================== + + //--------------------------------------------------------------------- + //--- 20.08.01 15:53:35 ----------------------------------------------- + + OConfigurationValueContainer::OConfigurationValueContainer( + const Reference< XMultiServiceFactory >& _rxORB, ::osl::Mutex& _rAccessSafety, + const sal_Char* _pConfigLocation, const sal_uInt16 _nAccessFlags, const sal_Int32 _nLevels ) + :m_pImpl( new OConfigurationValueContainerImpl( _rxORB, _rAccessSafety ) ) + { + implConstruct( ::rtl::OUString::createFromAscii( _pConfigLocation ), _nAccessFlags, _nLevels ); + } + + //--------------------------------------------------------------------- + //--- 20.08.01 15:55:20 ----------------------------------------------- + + OConfigurationValueContainer::OConfigurationValueContainer( + const Reference< XMultiServiceFactory >& _rxORB, ::osl::Mutex& _rAccessSafety, + const ::rtl::OUString& _rConfigLocation, const sal_uInt16 _nAccessFlags, const sal_Int32 _nLevels ) + :m_pImpl( new OConfigurationValueContainerImpl( _rxORB, _rAccessSafety ) ) + { + implConstruct( _rConfigLocation, _nAccessFlags, _nLevels ); + } + + //--------------------------------------------------------------------- + //--- 20.08.01 16:01:29 ----------------------------------------------- + + OConfigurationValueContainer::~OConfigurationValueContainer() + { + delete m_pImpl; + } + + //--------------------------------------------------------------------- + //--- 20.08.01 15:59:13 ----------------------------------------------- + + const Reference< XMultiServiceFactory >& OConfigurationValueContainer::getServiceFactory( ) const + { + return m_pImpl->xORB; + } + + //--------------------------------------------------------------------- + //--- 20.08.01 16:02:07 ----------------------------------------------- + + void OConfigurationValueContainer::implConstruct( const ::rtl::OUString& _rConfigLocation, + const sal_uInt16 _nAccessFlags, const sal_Int32 _nLevels ) + { + DBG_ASSERT( !m_pImpl->aConfigRoot.isValid(), "OConfigurationValueContainer::implConstruct: already initialized!" ); + + // ................................. + // create the configuration node we're about to work with + m_pImpl->aConfigRoot = OConfigurationTreeRoot::createWithServiceFactory( + m_pImpl->xORB, + _rConfigLocation, + _nLevels, + ( _nAccessFlags & CVC_UPDATE_ACCESS ) ? OConfigurationTreeRoot::CM_PREFER_UPDATABLE : OConfigurationTreeRoot::CM_READONLY, + ( _nAccessFlags & CVC_IMMEDIATE_UPDATE ) ? sal_False : sal_True + ); + #ifdef DBG_UTIL + rtl::OStringBuffer aBuf(256); + aBuf.append("Could not access the configuration node located at "); + aBuf.append( rtl::OUStringToOString( _rConfigLocation, RTL_TEXTENCODING_ASCII_US ) ); + aBuf.append( " !" ); + DBG_ASSERT( m_pImpl->aConfigRoot.isValid(), aBuf.getStr() ); + #endif + } + + //--------------------------------------------------------------------- + //--- 20.08.01 16:39:05 ----------------------------------------------- + + void OConfigurationValueContainer::registerExchangeLocation( const sal_Char* _pRelativePath, + void* _pContainer, const Type& _rValueType ) + { + // checks .... + DBG_ASSERT( _pContainer, "OConfigurationValueContainer::registerExchangeLocation: invalid container location!" ); + DBG_ASSERT( ( TypeClass_CHAR == _rValueType.getTypeClass( ) ) + || ( TypeClass_BOOLEAN == _rValueType.getTypeClass( ) ) + || ( TypeClass_BYTE == _rValueType.getTypeClass( ) ) + || ( TypeClass_SHORT == _rValueType.getTypeClass( ) ) + || ( TypeClass_LONG == _rValueType.getTypeClass( ) ) + || ( TypeClass_DOUBLE == _rValueType.getTypeClass( ) ) + || ( TypeClass_STRING == _rValueType.getTypeClass( ) ) + || ( TypeClass_SEQUENCE == _rValueType.getTypeClass( ) ), + "OConfigurationValueContainer::registerExchangeLocation: invalid type!" ); + + // build an accessor for this container + NodeValueAccessor aNewAccessor( ::rtl::OUString::createFromAscii( _pRelativePath ) ); + aNewAccessor.bind( _pContainer, _rValueType ); + + // insert it into our structure + implRegisterExchangeLocation( aNewAccessor ); + } + + //--------------------------------------------------------------------- + //--- 21.08.01 14:44:45 ----------------------------------------------- + + void OConfigurationValueContainer::registerNullValueExchangeLocation( const sal_Char* _pRelativePath, Any* _pContainer ) + { + // build an accessor for this container + NodeValueAccessor aNewAccessor( ::rtl::OUString::createFromAscii( _pRelativePath ) ); + aNewAccessor.bind( _pContainer ); + + // insert it into our structure + implRegisterExchangeLocation( aNewAccessor ); + } + + //--------------------------------------------------------------------- + //--- 21.08.01 10:23:34 ----------------------------------------------- + + void OConfigurationValueContainer::read( ) + { + for_each( + m_pImpl->aAccessors.begin(), + m_pImpl->aAccessors.end(), + UpdateFromConfig( m_pImpl->aConfigRoot, m_pImpl->rMutex ) + ); + } + + //--------------------------------------------------------------------- + //--- 21.08.01 12:04:48 ----------------------------------------------- + + void OConfigurationValueContainer::write( sal_Bool _bCommit ) + { + // collect the current values in the exchange locations + for_each( + m_pImpl->aAccessors.begin(), + m_pImpl->aAccessors.end(), + UpdateToConfig( m_pImpl->aConfigRoot, m_pImpl->rMutex ) + ); + + // commit the changes done (if requested) + if ( _bCommit ) + commit( sal_False ); + } + + //--------------------------------------------------------------------- + //--- 21.08.01 12:09:45 ----------------------------------------------- + + void OConfigurationValueContainer::commit( sal_Bool _bWrite ) + { + // write the current values in the exchange locations (if requested) + if ( _bWrite ) + write( sal_False ); + + // commit the changes done + m_pImpl->aConfigRoot.commit( ); + } + + //--------------------------------------------------------------------- + //--- 20.08.01 17:29:27 ----------------------------------------------- + + void OConfigurationValueContainer::implRegisterExchangeLocation( const NodeValueAccessor& _rAccessor ) + { + // some checks + DBG_ASSERT( !m_pImpl->aConfigRoot.isValid() || m_pImpl->aConfigRoot.hasByHierarchicalName( _rAccessor.getPath() ), + "OConfigurationValueContainer::implRegisterExchangeLocation: invalid relative path!" ); + +#ifdef DBG_UTIL + // another check (should be the first container for this node) + ConstNodeValueAccessorsIterator aExistent = ::std::find( + m_pImpl->aAccessors.begin(), + m_pImpl->aAccessors.end(), + _rAccessor + ); + DBG_ASSERT( m_pImpl->aAccessors.end() == aExistent, "OConfigurationValueContainer::implRegisterExchangeLocation: already registered a container for this subnode!" ); +#endif + + // remember the accessor + m_pImpl->aAccessors.push_back( _rAccessor ); + + // and initially fill the value + lcl_copyData( _rAccessor, m_pImpl->aConfigRoot.getNodeValue( _rAccessor.getPath() ), m_pImpl->rMutex ); + } + +//......................................................................... +} // namespace utl +//......................................................................... + diff --git a/unotools/source/config/docinfohelper.cxx b/unotools/source/config/docinfohelper.cxx new file mode 100644 index 000000000000..bd2fd4fd24ea --- /dev/null +++ b/unotools/source/config/docinfohelper.cxx @@ -0,0 +1,119 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: docinfohelper.cxx,v $ + * $Revision: 1.3 $ + * + * 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_unotools.hxx" + +#include <rtl/ustrbuf.hxx> +#include <tools/inetdef.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/bootstrap.hxx> +#include <unotools/docinfohelper.hxx> + +using namespace ::com::sun::star; + +namespace utl +{ + +::rtl::OUString DocInfoHelper::GetGeneratorString() +{ + rtl::OUStringBuffer aResult; + + // First product: branded name + version + // version is <product_versions>_<product_extension>$<platform> + utl::ConfigManager* pMgr = utl::ConfigManager::GetConfigManager(); + if ( pMgr ) + { + // plain product name + rtl::OUString aValue; + uno::Any aAny = pMgr->GetDirectConfigProperty( + utl::ConfigManager::PRODUCTNAME); + if ( (aAny >>= aValue) && aValue.getLength() ) + { + aResult.append( aValue.replace( ' ', '_' ) ); + aResult.append( (sal_Unicode)'/' ); + + aAny = pMgr->GetDirectConfigProperty( + utl::ConfigManager::PRODUCTVERSION); + if ( (aAny >>= aValue) && aValue.getLength() ) + { + aResult.append( aValue.replace( ' ', '_' ) ); + + aAny = pMgr->GetDirectConfigProperty( + utl::ConfigManager::PRODUCTEXTENSION); + if ( (aAny >>= aValue) && aValue.getLength() ) + { + aResult.append( (sal_Unicode)'_' ); + aResult.append( aValue.replace( ' ', '_' ) ); + } + } + + aResult.append( (sal_Unicode)'$' ); + aResult.append( ::rtl::OUString::createFromAscii( + TOOLS_INETDEF_OS ).replace( ' ', '_' ) ); + + aResult.append( (sal_Unicode)' ' ); + } + } + + // second product: OpenOffice.org_project/<build_information> + // build_information has '(' and '[' encoded as '$', ')' and ']' ignored + // and ':' replaced by '-' + { + aResult.appendAscii( "OpenOffice.org_project/" ); + ::rtl::OUString aDefault; + ::rtl::OUString aBuildId( Bootstrap::getBuildIdData( aDefault ) ); + for( sal_Int32 i=0; i < aBuildId.getLength(); i++ ) + { + sal_Unicode c = aBuildId[i]; + switch( c ) + { + case '(': + case '[': + aResult.append( (sal_Unicode)'$' ); + break; + case ')': + case ']': + break; + case ':': + aResult.append( (sal_Unicode)'-' ); + break; + default: + aResult.append( c ); + break; + } + } + } + + return aResult.makeStringAndClear(); +} + +} // end of namespace utl + diff --git a/unotools/source/config/makefile.mk b/unotools/source/config/makefile.mk new file mode 100644 index 000000000000..bd5a1b16512f --- /dev/null +++ b/unotools/source/config/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.15 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=config + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + + +# --- Files ------------------------------------- + +SLOFILES=\ + $(SLO)$/configvaluecontainer.obj \ + $(SLO)$/confignode.obj \ + $(SLO)$/configitem.obj \ + $(SLO)$/configmgr.obj \ + $(SLO)$/configpathes.obj \ + $(SLO)$/docinfohelper.obj \ + $(SLO)$/bootstrap.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/i18n/calendarwrapper.cxx b/unotools/source/i18n/calendarwrapper.cxx new file mode 100644 index 000000000000..1d83761b5cea --- /dev/null +++ b/unotools/source/i18n/calendarwrapper.cxx @@ -0,0 +1,683 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: calendarwrapper.cxx,v $ + * $Revision: 1.15.24.1 $ + * + * 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_unotools.hxx" + +#include <unotools/calendarwrapper.hxx> +#include <tools/string.hxx> +#include <tools/debug.hxx> + +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <com/sun/star/i18n/CalendarFieldIndex.hpp> +#include <com/sun/star/i18n/XExtendedCalendar.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#define CALENDAR_LIBRARYNAME "i18n" +#define CALENDAR_SERVICENAME "com.sun.star.i18n.LocaleCalendar" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::uno; + + +const double MILLISECONDS_PER_DAY = 1000.0 * 60.0 * 60.0 * 24.0; + + +CalendarWrapper::CalendarWrapper( + const Reference< lang::XMultiServiceFactory > & xSF + ) + : + xSMgr( xSF ), + aEpochStart( Date( 1, 1, 1970 ) ) +{ + if ( xSMgr.is() ) + { + try + { + xC = Reference< XExtendedCalendar > ( xSMgr->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CALENDAR_SERVICENAME ) ) ), + uno::UNO_QUERY ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "CalendarWrapper ctor: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + } + else + { // try to get an instance somehow + DBG_ERRORFILE( "CalendarWrapper: no service manager, trying own" ); + try + { + Reference< XInterface > xI = ::comphelper::getComponentInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( CALENDAR_LIBRARYNAME ) ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CALENDAR_SERVICENAME ) ) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const Reference< XExtendedCalendar >*)0) ); + x >>= xC; + } + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getComponentInstance: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + } +} + + +CalendarWrapper::~CalendarWrapper() +{ +} + + +void CalendarWrapper::loadDefaultCalendar( const ::com::sun::star::lang::Locale& rLocale ) +{ + try + { + if ( xC.is() ) + xC->loadDefaultCalendar( rLocale ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "loadDefaultCalendar: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +void CalendarWrapper::loadCalendar( const ::rtl::OUString& rUniqueID, const ::com::sun::star::lang::Locale& rLocale ) +{ + try + { + if ( xC.is() ) + xC->loadCalendar( rUniqueID, rLocale ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "loadCalendar: Exception caught\nrequested: " ); + aMsg += ByteString( String( rUniqueID ), RTL_TEXTENCODING_UTF8 ); + aMsg += " Locale: "; + aMsg += ByteString( String( rLocale.Language ), RTL_TEXTENCODING_UTF8 ); + aMsg += '_'; + aMsg += ByteString( String( rLocale.Country ), RTL_TEXTENCODING_UTF8 ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +::com::sun::star::i18n::Calendar CalendarWrapper::getLoadedCalendar() const +{ + try + { + if ( xC.is() ) + return xC->getLoadedCalendar(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getLoadedCalendar: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::i18n::Calendar(); +} + + +::com::sun::star::uno::Sequence< ::rtl::OUString > CalendarWrapper::getAllCalendars( const ::com::sun::star::lang::Locale& rLocale ) const +{ + try + { + if ( xC.is() ) + return xC->getAllCalendars( rLocale ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getAllCalendars: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::rtl::OUString > (0); +} + + +::rtl::OUString CalendarWrapper::getUniqueID() const +{ + try + { + if ( xC.is() ) + return xC->getUniqueID(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getUniqueID: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::rtl::OUString(); +} + + +void CalendarWrapper::setDateTime( double nTimeInDays ) +{ + try + { + if ( xC.is() ) + xC->setDateTime( nTimeInDays ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "setDateTime: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +double CalendarWrapper::getDateTime() const +{ + try + { + if ( xC.is() ) + return xC->getDateTime(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getDateTime: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0.0; +} + + +sal_Int32 CalendarWrapper::getCombinedOffsetInMillis( + sal_Int16 nParentFieldIndex, sal_Int16 nChildFieldIndex ) const +{ + sal_Int32 nOffset = 0; + try + { + if ( xC.is() ) + { + nOffset = static_cast<sal_Int32>( xC->getValue( nParentFieldIndex )) * 60000; + sal_Int16 nSecondMillis = xC->getValue( nChildFieldIndex ); + if (nOffset < 0) + nOffset -= static_cast<sal_uInt16>( nSecondMillis); + else + nOffset += static_cast<sal_uInt16>( nSecondMillis); + } + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "setLocalDateTime: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return nOffset; +} + + +sal_Int32 CalendarWrapper::getZoneOffsetInMillis() const +{ + return getCombinedOffsetInMillis( CalendarFieldIndex::ZONE_OFFSET, + CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS); +} + + +sal_Int32 CalendarWrapper::getDSTOffsetInMillis() const +{ + return getCombinedOffsetInMillis( CalendarFieldIndex::DST_OFFSET, + CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS); +} + + +void CalendarWrapper::setLocalDateTime( double nTimeInDays ) +{ + try + { + if ( xC.is() ) + { + // First set a nearby value to obtain the timezone and DST offset. + // This is necessary to let ICU choose the corresponding + // OlsonTimeZone transitions. Since ICU incorporates also + // historical data even the timezone may differ for different + // dates! (Which was the cause for #i76623# when the timezone of a + // previously set date was used.) Timezone may also include + // seconds, so use milliseconds field as well. + xC->setDateTime( nTimeInDays ); + sal_Int32 nZone1 = getZoneOffsetInMillis(); + sal_Int32 nDST1 = getDSTOffsetInMillis(); + double nLoc = nTimeInDays - (double)(nZone1 + nDST1) / MILLISECONDS_PER_DAY; + xC->setDateTime( nLoc ); + sal_Int32 nZone2 = getZoneOffsetInMillis(); + sal_Int32 nDST2 = getDSTOffsetInMillis(); + // If DSTs differ after calculation, we crossed boundaries. Do it + // again, this time using the DST corrected initial value for the + // real local time. + // See also localtime/gmtime conversion pitfalls at + // http://www.erack.de/download/timetest.c + if ( nDST1 != nDST2 ) + { + nLoc = nTimeInDays - (double)(nZone2 + nDST2) / MILLISECONDS_PER_DAY; + xC->setDateTime( nLoc ); + // #i17222# If the DST onset rule says to switch from 00:00 to + // 01:00 and we tried to set onsetDay 00:00 with DST, the + // result was onsetDay-1 23:00 and no DST, which is not what we + // want. So once again without DST, resulting in onsetDay + // 01:00 and DST. Yes, this seems to be weird, but logically + // correct. + sal_Int32 nDST3 = getDSTOffsetInMillis(); + if ( nDST2 != nDST3 && !nDST3 ) + { + nLoc = nTimeInDays - (double)(nZone2 + nDST3) / MILLISECONDS_PER_DAY; + xC->setDateTime( nLoc ); + } + } + } + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "setLocalDateTime: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +double CalendarWrapper::getLocalDateTime() const +{ + try + { + if ( xC.is() ) + { + double nTimeInDays = xC->getDateTime(); + sal_Int32 nZone = getZoneOffsetInMillis(); + sal_Int32 nDST = getDSTOffsetInMillis(); + nTimeInDays += (double)(nZone + nDST) / MILLISECONDS_PER_DAY; + return nTimeInDays; + } + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getLocalDateTime: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0.0; +} + + +void CalendarWrapper::setValue( sal_Int16 nFieldIndex, sal_Int16 nValue ) +{ + try + { + if ( xC.is() ) + xC->setValue( nFieldIndex, nValue ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "setValue: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +sal_Bool CalendarWrapper::isValid() const +{ + try + { + if ( xC.is() ) + return xC->isValid(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "isValid: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return sal_False; +} + + +sal_Int16 CalendarWrapper::getValue( sal_Int16 nFieldIndex ) const +{ + try + { + if ( xC.is() ) + return xC->getValue( nFieldIndex ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getValue: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +void CalendarWrapper::addValue( sal_Int16 nFieldIndex, sal_Int32 nAmount ) +{ + try + { + if ( xC.is() ) + xC->addValue( nFieldIndex, nAmount ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "addValue: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +sal_Int16 CalendarWrapper::getFirstDayOfWeek() const +{ + try + { + if ( xC.is() ) + return xC->getFirstDayOfWeek(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getFirstDayOfWeek: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +void CalendarWrapper::setFirstDayOfWeek( sal_Int16 nDay ) +{ + try + { + if ( xC.is() ) + xC->setFirstDayOfWeek( nDay ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "setFirstDayOfWeek: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +void CalendarWrapper::setMinimumNumberOfDaysForFirstWeek( sal_Int16 nDays ) +{ + try + { + if ( xC.is() ) + xC->setMinimumNumberOfDaysForFirstWeek( nDays ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "setMinimumNumberOfDaysForFirstWeek: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } +} + + +sal_Int16 CalendarWrapper::getMinimumNumberOfDaysForFirstWeek() const +{ + try + { + if ( xC.is() ) + return xC->getMinimumNumberOfDaysForFirstWeek(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getMinimumNumberOfDaysForFirstWeek: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +sal_Int16 CalendarWrapper::getNumberOfMonthsInYear() const +{ + try + { + if ( xC.is() ) + return xC->getNumberOfMonthsInYear(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getNumberOfMonthsInYear: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +sal_Int16 CalendarWrapper::getNumberOfDaysInWeek() const +{ + try + { + if ( xC.is() ) + return xC->getNumberOfDaysInWeek(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getNumberOfDaysInWeek: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > CalendarWrapper::getMonths() const +{ + try + { + if ( xC.is() ) + return xC->getMonths(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getMonths: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > (0); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > CalendarWrapper::getDays() const +{ + try + { + if ( xC.is() ) + return xC->getDays(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getDays: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > (0); +} + + +String CalendarWrapper::getDisplayName( sal_Int16 nCalendarDisplayIndex, sal_Int16 nIdx, sal_Int16 nNameType ) const +{ + try + { + if ( xC.is() ) + return xC->getDisplayName( nCalendarDisplayIndex, nIdx, nNameType ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getDisplayName: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return String(); +} + + +// --- XExtendedCalendar ----------------------------------------------------- + +String CalendarWrapper::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) const +{ + try + { + if ( xC.is() ) + return xC->getDisplayString( nCalendarDisplayCode, nNativeNumberMode ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "getDisplayString: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return String(); +} + diff --git a/unotools/source/i18n/charclass.cxx b/unotools/source/i18n/charclass.cxx new file mode 100644 index 000000000000..c1b6b4bc155c --- /dev/null +++ b/unotools/source/i18n/charclass.cxx @@ -0,0 +1,585 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: charclass.cxx,v $ + * $Revision: 1.13 $ + * + * 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_unotools.hxx" + +#include <unotools/charclass.hxx> +#include <tools/string.hxx> +#include <tools/debug.hxx> + +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#define CHARCLASS_LIBRARYNAME "i18n" +#define CHARCLASS_SERVICENAME "com.sun.star.i18n.CharacterClassification" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::uno; + + +CharClass::CharClass( + const Reference< lang::XMultiServiceFactory > & xSF, + const lang::Locale& rLocale + ) + : + xSMgr( xSF ) +{ + setLocale( rLocale ); + if ( xSMgr.is() ) + { + try + { + xCC = Reference< XCharacterClassification > ( xSMgr->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CHARCLASS_SERVICENAME ) ) ), + uno::UNO_QUERY ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "CharClass ctor: Exception caught!" ); + } + } + else + { // try to get an instance somehow + getComponentInstance(); + } +} + + +CharClass::CharClass( + const ::com::sun::star::lang::Locale& rLocale ) +{ + setLocale( rLocale ); + getComponentInstance(); +} + + +CharClass::~CharClass() +{ +} + + +void CharClass::getComponentInstance() +{ + try + { + // CharClass may be needed by "small tools" like the Setup + // => maybe no service manager => loadLibComponentFactory + Reference < XInterface > xI = ::comphelper::getComponentInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( CHARCLASS_LIBRARYNAME ) ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( CHARCLASS_SERVICENAME ) ) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const Reference< XCharacterClassification >*)0) ); + x >>= xCC; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getComponentInstance: Exception caught!" ); + } +} + + +void CharClass::setLocale( const ::com::sun::star::lang::Locale& rLocale ) +{ + ::osl::MutexGuard aGuard( aMutex ); + aLocale.Language = rLocale.Language; + aLocale.Country = rLocale.Country; + aLocale.Variant = rLocale.Variant; +} + + +const ::com::sun::star::lang::Locale& CharClass::getLocale() const +{ + ::osl::MutexGuard aGuard( aMutex ); + return aLocale; +} + + +// static +sal_Bool CharClass::isAsciiNumeric( const String& rStr ) +{ + if ( !rStr.Len() ) + return sal_False; + register const sal_Unicode* p = rStr.GetBuffer(); + register const sal_Unicode* const pStop = p + rStr.Len(); + do + { + if ( !isAsciiDigit( *p ) ) + return sal_False; + } while ( ++p < pStop ); + return sal_True; +} + + +// static +sal_Bool CharClass::isAsciiAlpha( const String& rStr ) +{ + if ( !rStr.Len() ) + return sal_False; + register const sal_Unicode* p = rStr.GetBuffer(); + register const sal_Unicode* const pStop = p + rStr.Len(); + do + { + if ( !isAsciiAlpha( *p ) ) + return sal_False; + } while ( ++p < pStop ); + return sal_True; +} + + +// static +sal_Bool CharClass::isAsciiAlphaNumeric( const String& rStr ) +{ + if ( !rStr.Len() ) + return sal_False; + register const sal_Unicode* p = rStr.GetBuffer(); + register const sal_Unicode* const pStop = p + rStr.Len(); + do + { + if ( !isAsciiAlphaNumeric( *p ) ) + return sal_False; + } while ( ++p < pStop ); + return sal_True; +} + + +sal_Bool CharClass::isAlpha( const String& rStr, xub_StrLen nPos ) const +{ + sal_Unicode c = rStr.GetChar( nPos ); + if ( c < 128 ) + return isAsciiAlpha( c ); + + try + { + if ( xCC.is() ) + return (xCC->getCharacterType( rStr, nPos, getLocale() ) & + nCharClassAlphaType) != 0; + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isAlpha: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isAlpha( const String& rStr ) const +{ + try + { + if ( xCC.is() ) + return isAlphaType( xCC->getStringType( rStr, 0, rStr.Len(), getLocale() ) ); + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isAlpha: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isLetter( const String& rStr, xub_StrLen nPos ) const +{ + sal_Unicode c = rStr.GetChar( nPos ); + if ( c < 128 ) + return isAsciiAlpha( c ); + + try + { + if ( xCC.is() ) + return (xCC->getCharacterType( rStr, nPos, getLocale() ) & + nCharClassLetterType) != 0; + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isLetter: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isLetter( const String& rStr ) const +{ + try + { + if ( xCC.is() ) + return isLetterType( xCC->getStringType( rStr, 0, rStr.Len(), getLocale() ) ); + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isLetter: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isDigit( const String& rStr, xub_StrLen nPos ) const +{ + sal_Unicode c = rStr.GetChar( nPos ); + if ( c < 128 ) + return isAsciiDigit( c ); + + try + { + if ( xCC.is() ) + return (xCC->getCharacterType( rStr, nPos, getLocale() ) & + KCharacterType::DIGIT) != 0; + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isDigit: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isNumeric( const String& rStr ) const +{ + try + { + if ( xCC.is() ) + return isNumericType( xCC->getStringType( rStr, 0, rStr.Len(), getLocale() ) ); + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isNumeric: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isAlphaNumeric( const String& rStr, xub_StrLen nPos ) const +{ + sal_Unicode c = rStr.GetChar( nPos ); + if ( c < 128 ) + return isAsciiAlphaNumeric( c ); + + try + { + if ( xCC.is() ) + return (xCC->getCharacterType( rStr, nPos, getLocale() ) & + (nCharClassAlphaType | KCharacterType::DIGIT)) != 0; + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isAlphaNumeric: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isAlphaNumeric( const String& rStr ) const +{ + try + { + if ( xCC.is() ) + return isAlphaNumericType( xCC->getStringType( rStr, 0, rStr.Len(), getLocale() ) ); + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isAlphaNumeric: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isLetterNumeric( const String& rStr, xub_StrLen nPos ) const +{ + sal_Unicode c = rStr.GetChar( nPos ); + if ( c < 128 ) + return isAsciiAlphaNumeric( c ); + + try + { + if ( xCC.is() ) + return (xCC->getCharacterType( rStr, nPos, getLocale() ) & + (nCharClassLetterType | KCharacterType::DIGIT)) != 0; + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isLetterNumeric: Exception caught!" ); + return sal_False; + } +} + + +sal_Bool CharClass::isLetterNumeric( const String& rStr ) const +{ + try + { + if ( xCC.is() ) + return isLetterNumericType( xCC->getStringType( rStr, 0, rStr.Len(), getLocale() ) ); + else + return sal_False; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "isLetterNumeric: Exception caught!" ); + return sal_False; + } +} + + +String CharClass::toUpper( const String& rStr, xub_StrLen nPos, xub_StrLen nCount ) const +{ + return toUpper_rtl(rStr, nPos, nCount); +} + + +String CharClass::toLower( const String& rStr, xub_StrLen nPos, xub_StrLen nCount ) const +{ + return toLower_rtl(::rtl::OUString(rStr), nPos, nCount); +} + + +String CharClass::toTitle( const String& rStr, xub_StrLen nPos, xub_StrLen nCount ) const +{ + try + { + if ( xCC.is() ) + return xCC->toTitle( rStr, nPos, nCount, getLocale() ); + else + return rStr.Copy( nPos, nCount ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "toTitle: Exception caught!" ); + return rStr.Copy( nPos, nCount ); + } +} + + +::rtl::OUString CharClass::toUpper_rtl( const ::rtl::OUString& rStr, sal_Int32 nPos, sal_Int32 nCount ) const +{ + try + { + if ( xCC.is() ) + return xCC->toUpper( rStr, nPos, nCount, getLocale() ); + else + return rStr.copy( nPos, nCount ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "toUpper: Exception caught!" ); + return rStr.copy( nPos, nCount ); + } +} + + +::rtl::OUString CharClass::toLower_rtl( const ::rtl::OUString& rStr, sal_Int32 nPos, sal_Int32 nCount ) const +{ + try + { + if ( xCC.is() ) + return xCC->toLower( rStr, nPos, nCount, getLocale() ); + else + return rStr.copy( nPos, nCount ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "toLower: Exception caught!" ); + return rStr.copy( nPos, nCount ); + } +} + + +sal_Int16 CharClass::getType( const String& rStr, xub_StrLen nPos ) const +{ + try + { + if ( xCC.is() ) + return xCC->getType( rStr, nPos ); + else + return 0; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getType: Exception caught!" ); + return 0; + } +} + + +sal_Int16 CharClass::getCharacterDirection( const String& rStr, xub_StrLen nPos ) const +{ + try + { + if ( xCC.is() ) + return xCC->getCharacterDirection( rStr, nPos ); + else + return 0; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getCharacterDirection: Exception caught!" ); + return 0; + } +} + + +sal_Int16 CharClass::getScript( const String& rStr, xub_StrLen nPos ) const +{ + try + { + if ( xCC.is() ) + return xCC->getScript( rStr, nPos ); + else + return 0; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getScript: Exception caught!" ); + return 0; + } +} + + +sal_Int32 CharClass::getCharacterType( const String& rStr, xub_StrLen nPos ) const +{ + try + { + if ( xCC.is() ) + return xCC->getCharacterType( rStr, nPos, getLocale() ); + else + return 0; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getCharacterType: Exception caught!" ); + return 0; + } +} + + +sal_Int32 CharClass::getStringType( const String& rStr, xub_StrLen nPos, xub_StrLen nCount ) const +{ + try + { + if ( xCC.is() ) + return xCC->getStringType( rStr, nPos, nCount, getLocale() ); + else + return 0; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getStringType: Exception caught!" ); + return 0; + } +} + + +::com::sun::star::i18n::ParseResult CharClass::parseAnyToken( + const String& rStr, + sal_Int32 nPos, + sal_Int32 nStartCharFlags, + const String& userDefinedCharactersStart, + sal_Int32 nContCharFlags, + const String& userDefinedCharactersCont ) const +{ + try + { + if ( xCC.is() ) + return xCC->parseAnyToken( rStr, nPos, getLocale(), + nStartCharFlags, userDefinedCharactersStart, + nContCharFlags, userDefinedCharactersCont ); + else + return ParseResult(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "parseAnyToken: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + return ParseResult(); + } +} + + +::com::sun::star::i18n::ParseResult CharClass::parsePredefinedToken( + sal_Int32 nTokenType, + const String& rStr, + sal_Int32 nPos, + sal_Int32 nStartCharFlags, + const String& userDefinedCharactersStart, + sal_Int32 nContCharFlags, + const String& userDefinedCharactersCont ) const +{ + try + { + if ( xCC.is() ) + return xCC->parsePredefinedToken( nTokenType, rStr, nPos, getLocale(), + nStartCharFlags, userDefinedCharactersStart, + nContCharFlags, userDefinedCharactersCont ); + else + return ParseResult(); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "parsePredefinedToken: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + return ParseResult(); + } +} + + + diff --git a/unotools/source/i18n/collatorwrapper.cxx b/unotools/source/i18n/collatorwrapper.cxx new file mode 100644 index 000000000000..99bb28cf6171 --- /dev/null +++ b/unotools/source/i18n/collatorwrapper.cxx @@ -0,0 +1,217 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: collatorwrapper.cxx,v $ + * $Revision: 1.8 $ + * + * 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_unotools.hxx" +#include <unotools/collatorwrapper.hxx> +#include <tools/debug.hxx> + +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +using namespace ::com::sun::star; + +CollatorWrapper::CollatorWrapper ( + const uno::Reference< lang::XMultiServiceFactory > &xServiceFactory) + : mxServiceFactory (xServiceFactory) +{ + ::rtl::OUString aService (RTL_CONSTASCII_USTRINGPARAM("com.sun.star.i18n.Collator")); + + if (mxServiceFactory.is()) + { + try + { + mxInternationalCollator = uno::Reference< i18n::XCollator > ( + mxServiceFactory->createInstance(aService), uno::UNO_QUERY); + } + catch (uno::Exception& rException) + { + (void)rException; + DBG_ERRORFILE ("CollatorWrapper: failed to create instance"); + } + } + else + { + ::rtl::OUString aLibrary (RTL_CONSTASCII_USTRINGPARAM(LLCF_LIBNAME("i18n"))); + + try + { + uno::Reference< uno::XInterface > xInstance = + ::comphelper::getComponentInstance (aLibrary, aService); + + if (xInstance.is()) + { + uno::Any xInterface = xInstance->queryInterface ( + ::getCppuType((const uno::Reference< i18n::XCollator >*)0) ); + xInterface >>= mxInternationalCollator; + } + } + catch (uno::Exception& rException) + { + (void)rException; + DBG_ERRORFILE ("CollatorWrapper: failed to get component instance!"); + } + } + + DBG_ASSERT (mxInternationalCollator.is(), "CollatorWrapper: no i18n collator"); +} + +CollatorWrapper::~CollatorWrapper() +{ +} + +sal_Int32 +CollatorWrapper::compareSubstring ( + const ::rtl::OUString& s1, sal_Int32 off1, sal_Int32 len1, + const ::rtl::OUString& s2, sal_Int32 off2, sal_Int32 len2) const +{ + try + { + if (mxInternationalCollator.is()) + return mxInternationalCollator->compareSubstring ( + s1, off1, len1, s2, off2, len2); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: compareSubstring failed"); + } + + return 0; +} + +sal_Int32 +CollatorWrapper::compareString (const ::rtl::OUString& s1, const ::rtl::OUString& s2) const +{ + try + { + if (mxInternationalCollator.is()) + return mxInternationalCollator->compareString (s1, s2); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: compareString failed"); + } + + return 0; +} + +uno::Sequence< ::rtl::OUString > +CollatorWrapper::listCollatorAlgorithms (const lang::Locale& rLocale) const +{ + try + { + if (mxInternationalCollator.is()) + return mxInternationalCollator->listCollatorAlgorithms (rLocale); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: listCollatorAlgorithms failed"); + } + + return uno::Sequence< ::rtl::OUString > (); +} + +uno::Sequence< sal_Int32 > +CollatorWrapper::listCollatorOptions (const ::rtl::OUString& rAlgorithm) const +{ + try + { + if (mxInternationalCollator.is()) + return mxInternationalCollator->listCollatorOptions (rAlgorithm); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: listCollatorOptions failed"); + } + + return uno::Sequence< sal_Int32 > (); +} + +sal_Int32 +CollatorWrapper::loadDefaultCollator (const lang::Locale& rLocale, sal_Int32 nOptions) +{ + try + { + if (mxInternationalCollator.is()) + return mxInternationalCollator->loadDefaultCollator (rLocale, nOptions); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: loadDefaultCollator failed"); + } + + return 0; +} + +sal_Int32 +CollatorWrapper::loadCollatorAlgorithm (const ::rtl::OUString& rAlgorithm, + const lang::Locale& rLocale, sal_Int32 nOptions) +{ + try + { + if (mxInternationalCollator.is()) + return mxInternationalCollator->loadCollatorAlgorithm ( + rAlgorithm, rLocale, nOptions); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: loadCollatorAlgorithm failed"); + } + + return 0; + +} + +void +CollatorWrapper::loadCollatorAlgorithmWithEndUserOption ( + const ::rtl::OUString& rAlgorithm, + const lang::Locale& rLocale, const uno::Sequence< sal_Int32 >& rOption) +{ + try + { + if (mxInternationalCollator.is()) + mxInternationalCollator->loadCollatorAlgorithmWithEndUserOption ( + rAlgorithm, rLocale, rOption); + } + catch (uno::RuntimeException& rRuntimeException) + { + (void)rRuntimeException; + DBG_ERRORFILE ("CollatorWrapper: loadCollatorAlgorithmWithEndUserOption failed"); + } +} diff --git a/unotools/source/i18n/intlwrapper.cxx b/unotools/source/i18n/intlwrapper.cxx new file mode 100644 index 000000000000..e961861da824 --- /dev/null +++ b/unotools/source/i18n/intlwrapper.cxx @@ -0,0 +1,113 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: intlwrapper.cxx,v $ + * $Revision: 1.7 $ + * + * 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_unotools.hxx" + +#include "unotools/intlwrapper.hxx" +#include <com/sun/star/i18n/CollatorOptions.hpp> +#include <i18npool/mslangid.hxx> + +IntlWrapper::IntlWrapper( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xSF, + const ::com::sun::star::lang::Locale& rLocale ) + : + aLocale( rLocale ), + xSMgr( xSF ), + pCharClass( NULL ), + pLocaleData( NULL ), + pCalendar( NULL ), + pCollator( NULL ), + pCaseCollator( NULL ) +{ + eLanguage = MsLangId::convertLocaleToLanguage( aLocale ); +} + + +IntlWrapper::IntlWrapper( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xSF, + LanguageType eLang ) + : + xSMgr( xSF ), + pCharClass( NULL ), + pLocaleData( NULL ), + pCalendar( NULL ), + pCollator( NULL ), + pCaseCollator( NULL ), + eLanguage( eLang ) +{ + MsLangId::convertLanguageToLocale( eLanguage, aLocale ); +} + + +IntlWrapper::~IntlWrapper() +{ + delete pCharClass; + delete pLocaleData; + delete pCalendar; + delete pCollator; + delete pCaseCollator; +} + + +void IntlWrapper::ImplNewCharClass() const +{ + ((IntlWrapper*)this)->pCharClass = new CharClass( xSMgr, aLocale ); +} + + +void IntlWrapper::ImplNewLocaleData() const +{ + ((IntlWrapper*)this)->pLocaleData = new LocaleDataWrapper( xSMgr, aLocale ); +} + + +void IntlWrapper::ImplNewCalendar() const +{ + CalendarWrapper* p = new CalendarWrapper( xSMgr ); + p->loadDefaultCalendar( aLocale ); + ((IntlWrapper*)this)->pCalendar = p; +} + + +void IntlWrapper::ImplNewCollator( BOOL bCaseSensitive ) const +{ + CollatorWrapper* p = new CollatorWrapper( xSMgr ); + if ( bCaseSensitive ) + { + p->loadDefaultCollator( aLocale, 0 ); + ((IntlWrapper*)this)->pCaseCollator = p; + } + else + { + p->loadDefaultCollator( aLocale, ::com::sun::star::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE ); + ((IntlWrapper*)this)->pCollator = p; + } +} diff --git a/unotools/source/i18n/localedatawrapper.cxx b/unotools/source/i18n/localedatawrapper.cxx new file mode 100644 index 000000000000..074ff7af716a --- /dev/null +++ b/unotools/source/i18n/localedatawrapper.cxx @@ -0,0 +1,2010 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: localedatawrapper.cxx,v $ + * $Revision: 1.43 $ + * + * 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_unotools.hxx" + +#include <string.h> // memcpy() +#include <stdio.h> // fprintf(), stderr + +#include <unotools/localedatawrapper.hxx> +#include <unotools/numberformatcodewrapper.hxx> +#include <unotools/calendarwrapper.hxx> +#include <unotools/digitgroupingiterator.hxx> +#include <tools/string.hxx> +#include <tools/debug.hxx> +#include <i18npool/mslangid.hxx> + +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <unotools/processfactory.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/KNumberFormatUsage.hpp> +#include <com/sun/star/i18n/KNumberFormatType.hpp> +#include <com/sun/star/i18n/CalendarFieldIndex.hpp> +#include <com/sun/star/i18n/CalendarDisplayIndex.hpp> + +#ifndef _COM_SUN_STAR_I18N_NUMBERFORMATINDEX_HPP_ +#include <com/sun/star/i18n/NumberFormatIndex.hdl> +#endif +#include <rtl/instance.hxx> + +#define LOCALEDATA_LIBRARYNAME "i18npool" +#define LOCALEDATA_SERVICENAME "com.sun.star.i18n.LocaleData" + +static const int nDateFormatInvalid = -1; +static const USHORT nCurrFormatInvalid = 0xffff; +static const USHORT nCurrFormatDefault = 0; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::uno; + +namespace +{ + struct InstalledLocales + : public rtl::Static< + uno::Sequence< lang::Locale >, InstalledLocales > + {}; + + struct InstalledLanguageTypes + : public rtl::Static< + uno::Sequence< sal_uInt16 >, InstalledLanguageTypes > + {}; +} + +BYTE LocaleDataWrapper::nLocaleDataChecking = 0; + +LocaleDataWrapper::LocaleDataWrapper( + const Reference< lang::XMultiServiceFactory > & xSF, + const lang::Locale& rLocale + ) + : + xSMgr( xSF ), + bLocaleDataItemValid( FALSE ), + bReservedWordValid( FALSE ) +{ + setLocale( rLocale ); + if ( xSMgr.is() ) + { + try + { + xLD = Reference< XLocaleData2 > ( xSMgr->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LOCALEDATA_SERVICENAME ) ) ), + uno::UNO_QUERY ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "LocaleDataWrapper ctor: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + } + else + { // try to get an instance somehow + DBG_ERRORFILE( "LocaleDataWrapper: no service manager, trying own" ); + try + { + Reference< XInterface > xI = ::comphelper::getComponentInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( LOCALEDATA_LIBRARYNAME ) ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LOCALEDATA_SERVICENAME ) ) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const Reference< XLocaleData2 >*)0) ); + x >>= xLD; + } + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getComponentInstance: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + } +} + + +LocaleDataWrapper::~LocaleDataWrapper() +{ +} + + +void LocaleDataWrapper::setLocale( const ::com::sun::star::lang::Locale& rLocale ) +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nCriticalChange ); + aLocale = rLocale; + invalidateData(); +} + + +const ::com::sun::star::lang::Locale& LocaleDataWrapper::getLocale() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + return aLocale; +} + + +void LocaleDataWrapper::invalidateData() +{ + aCurrSymbol.Erase(); + aCurrBankSymbol.Erase(); + nDateFormat = nLongDateFormat = nDateFormatInvalid; + nCurrPositiveFormat = nCurrNegativeFormat = nCurrDigits = nCurrFormatInvalid; + if ( bLocaleDataItemValid ) + { + for ( sal_Int32 j=0; j<LocaleItem::COUNT; j++ ) + { + aLocaleItem[j].Erase(); + } + bLocaleDataItemValid = FALSE; + } + if ( bReservedWordValid ) + { + for ( sal_Int16 j=0; j<reservedWords::COUNT; j++ ) + { + aReservedWord[j].Erase(); + } + bReservedWordValid = FALSE; + } + xDefaultCalendar.reset(); + if (aGrouping.getLength()) + aGrouping[0] = 0; + // dummies + cCurrZeroChar = '0'; +} + + +::com::sun::star::i18n::LanguageCountryInfo LocaleDataWrapper::getLanguageCountryInfo() const +{ + try + { + if ( xLD.is() ) + return xLD->getLanguageCountryInfo( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getLanguageCountryInfo: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::i18n::LanguageCountryInfo(); +} + + +::com::sun::star::i18n::LocaleDataItem LocaleDataWrapper::getLocaleItem() const +{ + try + { + if ( xLD.is() ) + return xLD->getLocaleItem( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getLocaleItem: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::i18n::LocaleDataItem(); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Calendar > LocaleDataWrapper::getAllCalendars() const +{ + try + { + if ( xLD.is() ) + return xLD->getAllCalendars( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getAllCalendars: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Calendar >(0); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 > LocaleDataWrapper::getAllCurrencies() const +{ + try + { + if ( xLD.is() ) + return xLD->getAllCurrencies2( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getAllCurrencies: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >(0); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::FormatElement > LocaleDataWrapper::getAllFormats() const +{ + try + { + if ( xLD.is() ) + return xLD->getAllFormats( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getAllFormats: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::FormatElement >(0); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Implementation > LocaleDataWrapper::getCollatorImplementations() const +{ + try + { + if ( xLD.is() ) + return xLD->getCollatorImplementations( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getCollatorImplementations: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Implementation >(0); +} + + +::com::sun::star::uno::Sequence< ::rtl::OUString > LocaleDataWrapper::getTransliterations() const +{ + try + { + if ( xLD.is() ) + return xLD->getTransliterations( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getTransliterations: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::rtl::OUString >(0); +} + + +::com::sun::star::i18n::ForbiddenCharacters LocaleDataWrapper::getForbiddenCharacters() const +{ + try + { + if ( xLD.is() ) + return xLD->getForbiddenCharacters( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getForbiddenCharacters: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::i18n::ForbiddenCharacters(); +} + + +::com::sun::star::uno::Sequence< ::rtl::OUString > LocaleDataWrapper::getReservedWord() const +{ + try + { + if ( xLD.is() ) + return xLD->getReservedWord( getLocale() ); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getReservedWord: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return ::com::sun::star::uno::Sequence< ::rtl::OUString >(0); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > LocaleDataWrapper::getAllInstalledLocaleNames() const +{ + uno::Sequence< lang::Locale > &rInstalledLocales = InstalledLocales::get(); + + if ( rInstalledLocales.getLength() ) + return rInstalledLocales; + + try + { + if ( xLD.is() ) + rInstalledLocales = xLD->getAllInstalledLocaleNames(); + } + catch ( Exception& e ) + { +#ifdef DBG_UTIL + ByteString aMsg( "getAllInstalledLocaleNames: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return rInstalledLocales; +} + + +// --- Impl and helpers ---------------------------------------------------- + +// static +::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > LocaleDataWrapper::getInstalledLocaleNames() +{ + const uno::Sequence< lang::Locale > &rInstalledLocales = + InstalledLocales::get(); + + if ( !rInstalledLocales.getLength() ) + { + LocaleDataWrapper aLDW( ::comphelper::getProcessServiceFactory(), lang::Locale() ); + aLDW.getAllInstalledLocaleNames(); + } + return rInstalledLocales; +} + +// static +::com::sun::star::uno::Sequence< sal_uInt16 > LocaleDataWrapper::getInstalledLanguageTypes() +{ + uno::Sequence< sal_uInt16 > &rInstalledLanguageTypes = + InstalledLanguageTypes::get(); + + if ( rInstalledLanguageTypes.getLength() ) + return rInstalledLanguageTypes; + + ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc = + getInstalledLocaleNames(); + sal_Int32 nCount = xLoc.getLength(); + ::com::sun::star::uno::Sequence< sal_uInt16 > xLang( nCount ); + sal_Int32 nLanguages = 0; + for ( sal_Int32 i=0; i<nCount; i++ ) + { + String aDebugLocale; + if (areChecksEnabled()) + { + aDebugLocale = xLoc[i].Language; + if ( xLoc[i].Country.getLength() ) + { + aDebugLocale += '_'; + aDebugLocale += String( xLoc[i].Country); + if ( xLoc[i].Variant.getLength() ) + { + aDebugLocale += '_'; + aDebugLocale += String( xLoc[i].Variant); + } + } + } + + if ( xLoc[i].Variant.getLength() ) + { + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getInstalledLanguageTypes: Variants not supported, locale\n")); + aMsg += aDebugLocale; + outputCheckMessage( aMsg ); + } + continue; + } + LanguageType eLang = MsLangId::convertLocaleToLanguage( xLoc[i] ); + + // In checks, exclude known problems because no MS-LCID defined. + if (areChecksEnabled() && eLang == LANGUAGE_DONTKNOW +// && !aDebugLocale.EqualsAscii( "br_AE" ) // ?!? Breton in United Arabic Emirates + ) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "ConvertIsoNamesToLanguage: unknown MS-LCID for locale\n")); + aMsg += aDebugLocale; + outputCheckMessage( aMsg ); + } + + switch ( eLang ) + { + case LANGUAGE_NORWEGIAN : // no_NO, not Bokmal (nb_NO), not Nynorsk (nn_NO) + eLang = LANGUAGE_DONTKNOW; // don't offer "Unknown" language + break; + } + if ( eLang != LANGUAGE_DONTKNOW ) + { + rtl::OUString aLanguage, aCountry; + MsLangId::convertLanguageToIsoNames( eLang, aLanguage, aCountry ); + if ( xLoc[i].Language != aLanguage || + xLoc[i].Country != aCountry ) + { + // In checks, exclude known problems because no MS-LCID defined + // and default for Language found. + if ( areChecksEnabled() + && !aDebugLocale.EqualsAscii( "ar_SD" ) // Sudan/ar + && !aDebugLocale.EqualsAscii( "en_CB" ) // Carribean is not a country +// && !aDebugLocale.EqualsAscii( "en_BG" ) // ?!? Bulgaria/en +// && !aDebugLocale.EqualsAscii( "es_BR" ) // ?!? Brazil/es + ) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "ConvertIsoNamesToLanguage/ConvertLanguageToIsoNames: ambiguous locale (MS-LCID?)\n")); + aMsg += aDebugLocale; + aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " -> 0x" ) ); + aMsg += String::CreateFromInt32( eLang, 16 ); + aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " -> " ) ); + aMsg += String( aLanguage); + if ( aCountry.getLength() ) + { + aMsg += '_'; + aMsg += String( aCountry); + } + outputCheckMessage( aMsg ); + } + eLang = LANGUAGE_DONTKNOW; + } + } + if ( eLang != LANGUAGE_DONTKNOW ) + xLang[ nLanguages++ ] = eLang; + } + if ( nLanguages < nCount ) + xLang.realloc( nLanguages ); + rInstalledLanguageTypes = xLang; + + return rInstalledLanguageTypes; +} + +const String& LocaleDataWrapper::getOneLocaleItem( sal_Int16 nItem ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nItem >= LocaleItem::COUNT ) + { + DBG_ERRORFILE( "getOneLocaleItem: bounds" ); + return aLocaleItem[0]; + } + if ( aLocaleItem[nItem].Len() == 0 ) + { // no cached content + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getOneLocaleItemImpl( nItem ); + } + return aLocaleItem[nItem]; +} + + +void LocaleDataWrapper::getOneLocaleItemImpl( sal_Int16 nItem ) +{ + if ( !bLocaleDataItemValid ) + { + aLocaleDataItem = getLocaleItem(); + bLocaleDataItemValid = TRUE; + } + switch ( nItem ) + { + case LocaleItem::DATE_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.dateSeparator; + break; + case LocaleItem::THOUSAND_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.thousandSeparator; + break; + case LocaleItem::DECIMAL_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.decimalSeparator; + break; + case LocaleItem::TIME_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.timeSeparator; + break; + case LocaleItem::TIME_100SEC_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.time100SecSeparator; + break; + case LocaleItem::LIST_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.listSeparator; + break; + case LocaleItem::SINGLE_QUOTATION_START : + aLocaleItem[nItem] = aLocaleDataItem.quotationStart; + break; + case LocaleItem::SINGLE_QUOTATION_END : + aLocaleItem[nItem] = aLocaleDataItem.quotationEnd; + break; + case LocaleItem::DOUBLE_QUOTATION_START : + aLocaleItem[nItem] = aLocaleDataItem.doubleQuotationStart; + break; + case LocaleItem::DOUBLE_QUOTATION_END : + aLocaleItem[nItem] = aLocaleDataItem.doubleQuotationEnd; + break; + case LocaleItem::MEASUREMENT_SYSTEM : + aLocaleItem[nItem] = aLocaleDataItem.measurementSystem; + break; + case LocaleItem::TIME_AM : + aLocaleItem[nItem] = aLocaleDataItem.timeAM; + break; + case LocaleItem::TIME_PM : + aLocaleItem[nItem] = aLocaleDataItem.timePM; + break; + case LocaleItem::LONG_DATE_DAY_OF_WEEK_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.LongDateDayOfWeekSeparator; + break; + case LocaleItem::LONG_DATE_DAY_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.LongDateDaySeparator; + break; + case LocaleItem::LONG_DATE_MONTH_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.LongDateMonthSeparator; + break; + case LocaleItem::LONG_DATE_YEAR_SEPARATOR : + aLocaleItem[nItem] = aLocaleDataItem.LongDateYearSeparator; + break; + default: + DBG_ERRORFILE( "getOneLocaleItemImpl: which one?" ); + } +} + + +void LocaleDataWrapper::getOneReservedWordImpl( sal_Int16 nWord ) +{ + if ( !bReservedWordValid ) + { + aReservedWordSeq = getReservedWord(); + bReservedWordValid = TRUE; + } + DBG_ASSERT( nWord < aReservedWordSeq.getLength(), "getOneReservedWordImpl: which one?" ); + if ( nWord < aReservedWordSeq.getLength() ) + aReservedWord[nWord] = aReservedWordSeq[nWord]; +} + + +const String& LocaleDataWrapper::getOneReservedWord( sal_Int16 nWord ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nWord < 0 || nWord >= reservedWords::COUNT ) + { + DBG_ERRORFILE( "getOneReservedWord: bounds" ); + nWord = reservedWords::FALSE_WORD; + } + if ( aReservedWord[nWord].Len() == 0 ) + { // no cached content + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getOneReservedWordImpl( nWord ); + } + return aReservedWord[nWord]; +} + + +MeasurementSystem LocaleDataWrapper::mapMeasurementStringToEnum( const String& rMS ) const +{ +//! TODO: could be cached too + if ( rMS.EqualsIgnoreCaseAscii( "metric" ) ) + return MEASURE_METRIC; +//! TODO: other measurement systems? => extend enum MeasurementSystem + return MEASURE_US; +} + + +void LocaleDataWrapper::getDefaultCalendarImpl() +{ + if (!xDefaultCalendar) + { + Sequence< Calendar > xCals = getAllCalendars(); + sal_Int32 nCount = xCals.getLength(); + sal_Int32 nDef = 0; + if (nCount > 1) + { + const Calendar* pArr = xCals.getArray(); + for (sal_Int32 i=0; i<nCount; ++i) + { + if (pArr[i].Default) + { + nDef = i; + break; + } + } + } + xDefaultCalendar.reset( new Calendar( xCals[nDef])); + } +} + + +const ::boost::shared_ptr< ::com::sun::star::i18n::Calendar > LocaleDataWrapper::getDefaultCalendar() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if (!xDefaultCalendar) + { // no cached content + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getDefaultCalendarImpl(); + } + return xDefaultCalendar; +} + + +const ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > LocaleDataWrapper::getDefaultCalendarDays() const +{ + return getDefaultCalendar()->Days; +} + + +const ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > LocaleDataWrapper::getDefaultCalendarMonths() const +{ + return getDefaultCalendar()->Months; +} + + +// --- currencies ----------------------------------------------------- + +const String& LocaleDataWrapper::getCurrSymbol() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( !aCurrSymbol.Len() ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getCurrSymbolsImpl(); + } + return aCurrSymbol; +} + + +const String& LocaleDataWrapper::getCurrBankSymbol() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( !aCurrBankSymbol.Len() ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getCurrSymbolsImpl(); + } + return aCurrBankSymbol; +} + + +USHORT LocaleDataWrapper::getCurrPositiveFormat() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nCurrPositiveFormat == nCurrFormatInvalid ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getCurrFormatsImpl(); + } + return nCurrPositiveFormat; +} + + +USHORT LocaleDataWrapper::getCurrNegativeFormat() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nCurrNegativeFormat == nCurrFormatInvalid ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getCurrFormatsImpl(); + } + return nCurrNegativeFormat; +} + + +USHORT LocaleDataWrapper::getCurrDigits() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nCurrDigits == nCurrFormatInvalid ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getCurrSymbolsImpl(); + } + return nCurrDigits; +} + + +void LocaleDataWrapper::getCurrSymbolsImpl() +{ + Sequence< Currency2 > aCurrSeq = getAllCurrencies(); + sal_Int32 nCnt = aCurrSeq.getLength(); + Currency2 const * const pCurrArr = aCurrSeq.getArray(); + sal_Int32 nElem; + for ( nElem = 0; nElem < nCnt; nElem++ ) + { + if ( pCurrArr[nElem].Default ) + break; + } + if ( nElem >= nCnt ) + { + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getCurrSymbolsImpl: no default currency")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + nElem = 0; + if ( nElem >= nCnt ) + { + if (areChecksEnabled()) + outputCheckMessage( String( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getCurrSymbolsImpl: no currency at all, using ShellsAndPebbles"))); + aCurrSymbol.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "ShellsAndPebbles" ) ); + aCurrBankSymbol = aCurrSymbol; + nCurrPositiveFormat = nCurrNegativeFormat = nCurrFormatDefault; + nCurrDigits = 2; + return ; + } + } + aCurrSymbol = pCurrArr[nElem].Symbol; + aCurrBankSymbol = pCurrArr[nElem].BankSymbol; + nCurrDigits = pCurrArr[nElem].DecimalPlaces; +} + + +void LocaleDataWrapper::scanCurrFormatImpl( const String& rCode, + xub_StrLen nStart, xub_StrLen& nSign, xub_StrLen& nPar, + xub_StrLen& nNum, xub_StrLen& nBlank, xub_StrLen& nSym ) +{ + nSign = nPar = nNum = nBlank = nSym = STRING_NOTFOUND; + const sal_Unicode* const pStr = rCode.GetBuffer(); + const sal_Unicode* const pStop = pStr + rCode.Len(); + const sal_Unicode* p = pStr + nStart; + int nInSection = 0; + BOOL bQuote = FALSE; + while ( p < pStop ) + { + if ( bQuote ) + { + if ( *p == '"' && *(p-1) != '\\' ) + bQuote = FALSE; + } + else + { + switch ( *p ) + { + case '"' : + if ( pStr == p || *(p-1) != '\\' ) + bQuote = TRUE; + break; + case '-' : + if ( !nInSection && nSign == STRING_NOTFOUND ) + nSign = (xub_StrLen)(p - pStr); + break; + case '(' : + if ( !nInSection && nPar == STRING_NOTFOUND ) + nPar = (xub_StrLen)(p - pStr); + break; + case '0' : + case '#' : + if ( !nInSection && nNum == STRING_NOTFOUND ) + nNum = (xub_StrLen)(p - pStr); + break; + case '[' : + nInSection++; + break; + case ']' : + if ( nInSection ) + { + nInSection--; + if ( !nInSection && nBlank == STRING_NOTFOUND + && nSym != STRING_NOTFOUND && p < pStop-1 && *(p+1) == ' ' ) + nBlank = (xub_StrLen)(p - pStr + 1); + } + break; + case '$' : + if ( nSym == STRING_NOTFOUND && nInSection && *(p-1) == '[' ) + { + nSym = (xub_StrLen)(p - pStr + 1); + if ( nNum != STRING_NOTFOUND && *(p-2) == ' ' ) + nBlank = (xub_StrLen)(p - pStr - 2); + } + break; + case ';' : + if ( !nInSection ) + p = pStop; + break; + default: + if ( !nInSection && nSym == STRING_NOTFOUND && rCode.Equals( aCurrSymbol, (xub_StrLen)(p-pStr), aCurrSymbol.Len() ) ) + { // currency symbol not surrounded by [$...] + nSym = (xub_StrLen)(p - pStr); + if ( nBlank == STRING_NOTFOUND && pStr < p && *(p-1) == ' ' ) + nBlank = (xub_StrLen)(p - pStr - 1); + p += aCurrSymbol.Len() - 1; + if ( nBlank == STRING_NOTFOUND && p < pStop-2 && *(p+2) == ' ' ) + nBlank = (xub_StrLen)(p - pStr + 2); + } + } + } + p++; + } +} + + +void LocaleDataWrapper::getCurrFormatsImpl() +{ + NumberFormatCodeWrapper aNumberFormatCode( xSMgr, getLocale() ); + uno::Sequence< NumberFormatCode > aFormatSeq + = aNumberFormatCode.getAllFormatCode( KNumberFormatUsage::CURRENCY ); + sal_Int32 nCnt = aFormatSeq.getLength(); + if ( !nCnt ) + { // bad luck + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getCurrFormatsImpl: no currency formats")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + nCurrPositiveFormat = nCurrNegativeFormat = nCurrFormatDefault; + return ; + } + // find a negative code (medium preferred) and a default (medium preferred) (not necessarily the same) + NumberFormatCode const * const pFormatArr = aFormatSeq.getArray(); + sal_Int32 nElem, nDef, nNeg, nMedium; + nDef = nNeg = nMedium = -1; + for ( nElem = 0; nElem < nCnt; nElem++ ) + { + if ( pFormatArr[nElem].Type == KNumberFormatType::MEDIUM ) + { + if ( pFormatArr[nElem].Default ) + { + nDef = nElem; + nMedium = nElem; + if ( pFormatArr[nElem].Code.indexOf( ';' ) >= 0 ) + nNeg = nElem; + } + else + { + if ( (nNeg == -1 || nMedium == -1) && pFormatArr[nElem].Code.indexOf( ';' ) >= 0 ) + nNeg = nElem; + if ( nMedium == -1 ) + nMedium = nElem; + } + } + else + { + if ( nDef == -1 && pFormatArr[nElem].Default ) + nDef = nElem; + if ( nNeg == -1 && pFormatArr[nElem].Code.indexOf( ';' ) >= 0 ) + nNeg = nElem; + } + } + + // make sure it's loaded + getCurrSymbol(); + + xub_StrLen nSign, nPar, nNum, nBlank, nSym; + + // positive format + nElem = (nDef >= 0 ? nDef : (nNeg >= 0 ? nNeg : 0)); + scanCurrFormatImpl( pFormatArr[nElem].Code, 0, nSign, nPar, nNum, nBlank, nSym ); + if (areChecksEnabled() && (nNum == STRING_NOTFOUND || nSym == STRING_NOTFOUND)) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getCurrFormatsImpl: CurrPositiveFormat?")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + if ( nBlank == STRING_NOTFOUND ) + { + if ( nSym < nNum ) + nCurrPositiveFormat = 0; // $1 + else + nCurrPositiveFormat = 1; // 1$ + } + else + { + if ( nSym < nNum ) + nCurrPositiveFormat = 2; // $ 1 + else + nCurrPositiveFormat = 3; // 1 $ + } + + // negative format + if ( nNeg < 0 ) + nCurrNegativeFormat = nCurrFormatDefault; + else + { + const ::rtl::OUString& rCode = pFormatArr[nNeg].Code; + xub_StrLen nDelim = (xub_StrLen)rCode.indexOf( ';' ); + scanCurrFormatImpl( rCode, nDelim+1, nSign, nPar, nNum, nBlank, nSym ); + if (areChecksEnabled() && (nNum == STRING_NOTFOUND || + nSym == STRING_NOTFOUND || (nPar == STRING_NOTFOUND && + nSign == STRING_NOTFOUND))) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getCurrFormatsImpl: CurrNegativeFormat?")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + if ( nBlank == STRING_NOTFOUND ) + { + if ( nSym < nNum ) + { + if ( nPar < nSym ) + nCurrNegativeFormat = 0; // ($1) + else if ( nSign < nSym ) + nCurrNegativeFormat = 1; // -$1 + else if ( nNum < nSign ) + nCurrNegativeFormat = 3; // $1- + else + nCurrNegativeFormat = 2; // $-1 + } + else + { + if ( nPar < nNum ) + nCurrNegativeFormat = 4; // (1$) + else if ( nSign < nNum ) + nCurrNegativeFormat = 5; // -1$ + else if ( nSym < nSign ) + nCurrNegativeFormat = 7; // 1$- + else + nCurrNegativeFormat = 6; // 1-$ + } + } + else + { + if ( nSym < nNum ) + { + if ( nPar < nSym ) + nCurrNegativeFormat = 14; // ($ 1) + else if ( nSign < nSym ) + nCurrNegativeFormat = 9; // -$ 1 + else if ( nNum < nSign ) + nCurrNegativeFormat = 12; // $ 1- + else + nCurrNegativeFormat = 11; // $ -1 + } + else + { + if ( nPar < nNum ) + nCurrNegativeFormat = 15; // (1 $) + else if ( nSign < nNum ) + nCurrNegativeFormat = 8; // -1 $ + else if ( nSym < nSign ) + nCurrNegativeFormat = 10; // 1 $- + else + nCurrNegativeFormat = 13; // 1- $ + } + } + } +} + + +// --- date ----------------------------------------------------------- + +DateFormat LocaleDataWrapper::getDateFormat() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nDateFormat == nDateFormatInvalid ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getDateFormatsImpl(); + } + return (DateFormat) nDateFormat; +} + + +DateFormat LocaleDataWrapper::getLongDateFormat() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if ( nLongDateFormat == nDateFormatInvalid ) + { + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getDateFormatsImpl(); + } + return (DateFormat) nLongDateFormat; +} + + +DateFormat LocaleDataWrapper::scanDateFormatImpl( const String& rCode ) +{ + // Only some european versions were translated, the ones with different + // keyword combinations are: + // English DMY, German TMJ, Spanish DMA, French JMA, Italian GMA, + // Dutch DMJ, Finnish PKV + + // default is English keywords for every other language + xub_StrLen nDay = rCode.Search( 'D' ); + xub_StrLen nMonth = rCode.Search( 'M' ); + xub_StrLen nYear = rCode.Search( 'Y' ); + if ( nDay == STRING_NOTFOUND || nMonth == STRING_NOTFOUND || nYear == STRING_NOTFOUND ) + { // This algorithm assumes that all three parts (DMY) are present + if ( nMonth == STRING_NOTFOUND ) + { // only Finnish has something else than 'M' for month + nMonth = rCode.Search( 'K' ); + if ( nMonth != STRING_NOTFOUND ) + { + nDay = rCode.Search( 'P' ); + nYear = rCode.Search( 'V' ); + } + } + else if ( nDay == STRING_NOTFOUND ) + { // We have a month 'M' if we reach this branch. + // Possible languages containing 'M' but no 'D': + // German, French, Italian + nDay = rCode.Search( 'T' ); // German + if ( nDay != STRING_NOTFOUND ) + nYear = rCode.Search( 'J' ); + else + { + nYear = rCode.Search( 'A' ); // French, Italian + if ( nYear != STRING_NOTFOUND ) + { + nDay = rCode.Search( 'J' ); // French + if ( nDay == STRING_NOTFOUND ) + nDay = rCode.Search( 'G' ); // Italian + } + } + } + else + { // We have a month 'M' and a day 'D'. + // Possible languages containing 'D' and 'M' but not 'Y': + // Spanish, Dutch + nYear = rCode.Search( 'A' ); // Spanish + if ( nYear == STRING_NOTFOUND ) + nYear = rCode.Search( 'J' ); // Dutch + } + if ( nDay == STRING_NOTFOUND || nMonth == STRING_NOTFOUND || nYear == STRING_NOTFOUND ) + { + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::scanDateFormat: not all DMY present")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + if ( nDay == STRING_NOTFOUND ) + nDay = rCode.Len(); + if ( nMonth == STRING_NOTFOUND ) + nMonth = rCode.Len(); + if ( nYear == STRING_NOTFOUND ) + nYear = rCode.Len(); + } + } + // compare with <= because each position may equal rCode.Len() + if ( nDay <= nMonth && nMonth <= nYear ) + return DMY; // also if every position equals rCode.Len() + else if ( nMonth <= nDay && nDay <= nYear ) + return MDY; + else if ( nYear <= nMonth && nMonth <= nDay ) + return YMD; + else + { + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::scanDateFormat: no magic applyable")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + return DMY; + } +} + + +void LocaleDataWrapper::getDateFormatsImpl() +{ + NumberFormatCodeWrapper aNumberFormatCode( xSMgr, getLocale() ); + uno::Sequence< NumberFormatCode > aFormatSeq + = aNumberFormatCode.getAllFormatCode( KNumberFormatUsage::DATE ); + sal_Int32 nCnt = aFormatSeq.getLength(); + if ( !nCnt ) + { // bad luck + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getDateFormatsImpl: no date formats")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + nDateFormat = nLongDateFormat = DMY; + return ; + } + // find the edit (21), a default (medium preferred), + // a medium (default preferred), and a long (default preferred) + NumberFormatCode const * const pFormatArr = aFormatSeq.getArray(); + sal_Int32 nElem, nEdit, nDef, nMedium, nLong; + nEdit = nDef = nMedium = nLong = -1; + for ( nElem = 0; nElem < nCnt; nElem++ ) + { + if ( nEdit == -1 && pFormatArr[nElem].Index == NumberFormatIndex::DATE_SYS_DDMMYYYY ) + nEdit = nElem; + if ( nDef == -1 && pFormatArr[nElem].Default ) + nDef = nElem; + switch ( pFormatArr[nElem].Type ) + { + case KNumberFormatType::MEDIUM : + { + if ( pFormatArr[nElem].Default ) + { + nDef = nElem; + nMedium = nElem; + } + else if ( nMedium == -1 ) + nMedium = nElem; + } + break; + case KNumberFormatType::LONG : + { + if ( pFormatArr[nElem].Default ) + nLong = nElem; + else if ( nLong == -1 ) + nLong = nElem; + } + break; + } + } + if ( nEdit == -1 ) + { + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getDateFormatsImpl: no edit")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + if ( nDef == -1 ) + { + if (areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "LocaleDataWrapper::getDateFormatsImpl: no default")); + outputCheckMessage( appendLocaleInfo( aMsg ) ); + } + if ( nMedium != -1 ) + nDef = nMedium; + else if ( nLong != -1 ) + nDef = nLong; + else + nDef = 0; + } + nEdit = nDef; + } + DateFormat nDF = scanDateFormatImpl( pFormatArr[nEdit].Code ); + if ( pFormatArr[nEdit].Type == KNumberFormatType::LONG ) + { // normally this is not the case + nLongDateFormat = nDateFormat = nDF; + } + else + { + nDateFormat = nDF; + if ( nLong == -1 ) + nLongDateFormat = nDF; + else + nLongDateFormat = scanDateFormatImpl( pFormatArr[nLong].Code ); + } +} + + +// --- digit grouping ------------------------------------------------- + +void LocaleDataWrapper::getDigitGroupingImpl() +{ + /* TODO: This is a very simplified grouping setup that only serves its + * current purpose for Indian locales. A free-form flexible one would + * obtain grouping from locale data where it could be specified using, for + * example, codes like #,### and #,##,### that would generate the integer + * sequence. Needed additional API and a locale data element. + */ + + if (!aGrouping.getLength()) + { + aGrouping.realloc(3); // room for {3,2,0} + aGrouping[0] = 0; // invalidate + } + if (!aGrouping[0]) + { + i18n::LanguageCountryInfo aLCInfo( getLanguageCountryInfo()); + if (aLCInfo.Country.equalsIgnoreAsciiCaseAscii( "IN") || // India + aLCInfo.Country.equalsIgnoreAsciiCaseAscii( "BT")) // Bhutan + { + aGrouping[0] = 3; + aGrouping[1] = 2; + aGrouping[2] = 0; + } + else + { + aGrouping[0] = 3; + aGrouping[1] = 0; + } + } +} + + +const ::com::sun::star::uno::Sequence< sal_Int32 > LocaleDataWrapper::getDigitGrouping() const +{ + ::utl::ReadWriteGuard aGuard( aMutex ); + if (!aGrouping.getLength() || aGrouping[0] == 0) + { // no cached content + aGuard.changeReadToWrite(); + ((LocaleDataWrapper*)this)->getDigitGroupingImpl(); + } + return aGrouping; +} + + +// --- simple number formatting helpers ------------------------------- + +// The ImplAdd... methods are taken from class International and modified to +// suit the needs. + +static sal_Unicode* ImplAddUNum( sal_Unicode* pBuf, sal_uInt64 nNumber ) +{ + // fill temp buffer with digits + sal_Unicode aTempBuf[64]; + sal_Unicode* pTempBuf = aTempBuf; + do + { + *pTempBuf = (sal_Unicode)(nNumber % 10) + '0'; + pTempBuf++; + nNumber /= 10; + } + while ( nNumber ); + + // copy temp buffer to buffer passed + do + { + pTempBuf--; + *pBuf = *pTempBuf; + pBuf++; + } + while ( pTempBuf != aTempBuf ); + + return pBuf; +} + + +static sal_Unicode* ImplAddUNum( sal_Unicode* pBuf, sal_uInt64 nNumber, int nMinLen ) +{ + // fill temp buffer with digits + sal_Unicode aTempBuf[64]; + sal_Unicode* pTempBuf = aTempBuf; + do + { + *pTempBuf = (sal_Unicode)(nNumber % 10) + '0'; + pTempBuf++; + nNumber /= 10; + nMinLen--; + } + while ( nNumber ); + + // fill with zeros up to the minimal length + while ( nMinLen > 0 ) + { + *pBuf = '0'; + pBuf++; + nMinLen--; + } + + // copy temp buffer to real buffer + do + { + pTempBuf--; + *pBuf = *pTempBuf; + pBuf++; + } + while ( pTempBuf != aTempBuf ); + + return pBuf; +} + + +static sal_Unicode* ImplAdd2UNum( sal_Unicode* pBuf, USHORT nNumber, int bLeading ) +{ + DBG_ASSERT( nNumber < 100, "ImplAdd2UNum() - Number >= 100" ); + + if ( nNumber < 10 ) + { + if ( bLeading ) + { + *pBuf = '0'; + pBuf++; + } + *pBuf = nNumber + '0'; + } + else + { + USHORT nTemp = nNumber % 10; + nNumber /= 10; + *pBuf = nNumber + '0'; + pBuf++; + *pBuf = nTemp + '0'; + } + + pBuf++; + return pBuf; +} + + +inline sal_Unicode* ImplAddString( sal_Unicode* pBuf, const String& rStr ) +{ + if ( rStr.Len() == 1 ) + *pBuf++ = rStr.GetChar(0); + else if ( rStr.Len() == 0 ) + ; + else + { + memcpy( pBuf, rStr.GetBuffer(), rStr.Len() * sizeof(sal_Unicode) ); + pBuf += rStr.Len(); + } + return pBuf; +} + + +inline sal_Unicode* ImplAddString( sal_Unicode* pBuf, sal_Unicode c ) +{ + *pBuf = c; + pBuf++; + return pBuf; +} + + +inline sal_Unicode* ImplAddString( sal_Unicode* pBuf, const sal_Unicode* pCopyBuf, xub_StrLen nLen ) +{ + memcpy( pBuf, pCopyBuf, nLen * sizeof(sal_Unicode) ); + return pBuf + nLen; +} + + +sal_Unicode* LocaleDataWrapper::ImplAddFormatNum( sal_Unicode* pBuf, + sal_Int64 nNumber, USHORT nDecimals, BOOL bUseThousandSep, + BOOL bTrailingZeros ) const +{ + sal_Unicode aNumBuf[64]; + sal_Unicode* pNumBuf; + USHORT nNumLen; + USHORT i = 0; + BOOL bNeg; + + // negative number + if ( nNumber < 0 ) + { + nNumber *= -1; + bNeg = TRUE; + *pBuf = '-'; + pBuf++; + } + else + bNeg = FALSE; + + // convert number + pNumBuf = ImplAddUNum( aNumBuf, (sal_uInt64)nNumber ); + nNumLen = (USHORT)(ULONG)(pNumBuf-aNumBuf); + pNumBuf = aNumBuf; + + if ( nNumLen <= nDecimals ) + { + // strip .0 in decimals? + if ( !nNumber && !bTrailingZeros ) + { + *pBuf = '0'; + pBuf++; + } + else + { + // LeadingZero, insert 0 + if ( isNumLeadingZero() ) + { + *pBuf = '0'; + pBuf++; + } + + // append decimal separator + pBuf = ImplAddString( pBuf, getNumDecimalSep() ); + + // fill with zeros + while ( i < (nDecimals-nNumLen) ) + { + *pBuf = '0'; + pBuf++; + i++; + } + + // append decimals + while ( nNumLen ) + { + *pBuf = *pNumBuf; + pBuf++; + pNumBuf++; + nNumLen--; + } + } + } + else + { + const String& rThoSep = getNumThousandSep(); + + // copy number to buffer (excluding decimals) + USHORT nNumLen2 = nNumLen-nDecimals; + uno::Sequence< sal_Bool > aGroupPos; + if (bUseThousandSep) + aGroupPos = utl::DigitGroupingIterator::createForwardSequence( + nNumLen2, getDigitGrouping()); + for ( ; i < nNumLen2; ++i ) + { + *pBuf = *pNumBuf; + pBuf++; + pNumBuf++; + + // add thousand separator? + if ( bUseThousandSep && aGroupPos[i] ) + pBuf = ImplAddString( pBuf, rThoSep ); + } + + // append decimals + if ( nDecimals ) + { + pBuf = ImplAddString( pBuf, getNumDecimalSep() ); + + BOOL bNullEnd = TRUE; + while ( i < nNumLen ) + { + if ( *pNumBuf != '0' ) + bNullEnd = FALSE; + + *pBuf = *pNumBuf; + pBuf++; + pNumBuf++; + i++; + } + + // strip .0 in decimals? + if ( bNullEnd && !bTrailingZeros ) + pBuf -= nDecimals+1; + } + } + + return pBuf; +} + + +// --- simple date and time formatting -------------------------------- + +String LocaleDataWrapper::getDate( const Date& rDate ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); +//!TODO: leading zeros et al + sal_Unicode aBuf[128]; + sal_Unicode* pBuf = aBuf; + USHORT nDay = rDate.GetDay(); + USHORT nMonth = rDate.GetMonth(); + USHORT nYear = rDate.GetYear(); + USHORT nYearLen; + + if ( TRUE /* IsDateCentury() */ ) + nYearLen = 4; + else + { + nYearLen = 2; + nYear %= 100; + } + + switch ( getDateFormat() ) + { + case DMY : + pBuf = ImplAdd2UNum( pBuf, nDay, TRUE /* IsDateDayLeadingZero() */ ); + pBuf = ImplAddString( pBuf, getDateSep() ); + pBuf = ImplAdd2UNum( pBuf, nMonth, TRUE /* IsDateMonthLeadingZero() */ ); + pBuf = ImplAddString( pBuf, getDateSep() ); + pBuf = ImplAddUNum( pBuf, nYear, nYearLen ); + break; + case MDY : + pBuf = ImplAdd2UNum( pBuf, nMonth, TRUE /* IsDateMonthLeadingZero() */ ); + pBuf = ImplAddString( pBuf, getDateSep() ); + pBuf = ImplAdd2UNum( pBuf, nDay, TRUE /* IsDateDayLeadingZero() */ ); + pBuf = ImplAddString( pBuf, getDateSep() ); + pBuf = ImplAddUNum( pBuf, nYear, nYearLen ); + break; + default: + pBuf = ImplAddUNum( pBuf, nYear, nYearLen ); + pBuf = ImplAddString( pBuf, getDateSep() ); + pBuf = ImplAdd2UNum( pBuf, nMonth, TRUE /* IsDateMonthLeadingZero() */ ); + pBuf = ImplAddString( pBuf, getDateSep() ); + pBuf = ImplAdd2UNum( pBuf, nDay, TRUE /* IsDateDayLeadingZero() */ ); + } + + return String( aBuf, (xub_StrLen)(ULONG)(pBuf-aBuf) ); +} + + +String LocaleDataWrapper::getTime( const Time& rTime, BOOL bSec, BOOL b100Sec ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); +//!TODO: leading zeros et al + sal_Unicode aBuf[128]; + sal_Unicode* pBuf = aBuf; + USHORT nHour = rTime.GetHour(); + BOOL bHour12 = FALSE; //!TODO: AM/PM from default time format code + + if ( bHour12 ) + { + nHour %= 12; + // 0:00 -> 12:00 + if ( !nHour ) + nHour = 12; + } + else + nHour %= 24; + + pBuf = ImplAdd2UNum( pBuf, nHour, TRUE /* IsTimeLeadingZero() */ ); + pBuf = ImplAddString( pBuf, getTimeSep() ); + pBuf = ImplAdd2UNum( pBuf, rTime.GetMin(), TRUE ); + if ( bSec ) + { + pBuf = ImplAddString( pBuf, getTimeSep() ); + pBuf = ImplAdd2UNum( pBuf, rTime.GetSec(), TRUE ); + + if ( b100Sec ) + { + pBuf = ImplAddString( pBuf, getTime100SecSep() ); + pBuf = ImplAdd2UNum( pBuf, rTime.Get100Sec(), TRUE ); + } + } + + String aStr( aBuf, (xub_StrLen)(ULONG)(pBuf-aBuf) ); + + if ( bHour12 ) + { + if ( (rTime.GetHour() % 24) >= 12 ) + aStr += getTimePM(); + else + aStr += getTimeAM(); + } +#if 0 +//!TODO: do we need a time string? like "o'clock" or "Uhr" or similar + else + aStr += getTimeStr(); +#endif + + return aStr; +} + + +String LocaleDataWrapper::getLongDate( const Date& rDate, CalendarWrapper& rCal, + sal_Int16 nDisplayDayOfWeek, sal_Bool bDayOfMonthWithLeadingZero, + sal_Int16 nDisplayMonth, sal_Bool bTwoDigitYear ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); + using namespace ::com::sun::star::i18n; + sal_Unicode aBuf[20]; + sal_Unicode* pBuf; + String aStr; + sal_Int16 nVal; + rCal.setGregorianDateTime( rDate ); + // day of week + nVal = rCal.getValue( CalendarFieldIndex::DAY_OF_WEEK ); + aStr += rCal.getDisplayName( CalendarDisplayIndex::DAY, nVal, nDisplayDayOfWeek ); + aStr += getLongDateDayOfWeekSep(); + // day of month + nVal = rCal.getValue( CalendarFieldIndex::DAY_OF_MONTH ); + pBuf = ImplAdd2UNum( aBuf, nVal, bDayOfMonthWithLeadingZero ); + String aDay( aBuf, (xub_StrLen)(ULONG)(pBuf-aBuf) ); + // month of year + nVal = rCal.getValue( CalendarFieldIndex::MONTH ); + String aMonth( rCal.getDisplayName( CalendarDisplayIndex::MONTH, nVal, nDisplayMonth ) ); + // year + nVal = rCal.getValue( CalendarFieldIndex::YEAR ); + if ( bTwoDigitYear ) + pBuf = ImplAddUNum( aBuf, nVal % 100, 2 ); + else + pBuf = ImplAddUNum( aBuf, nVal ); + String aYear( aBuf, (xub_StrLen)(ULONG)(pBuf-aBuf) ); + // concatenate + switch ( getLongDateFormat() ) + { + case DMY : + aStr += aDay; + aStr += getLongDateDaySep(); + aStr += aMonth; + aStr += getLongDateMonthSep(); + aStr += aYear; + break; + case MDY : + aStr += aMonth; + aStr += getLongDateMonthSep(); + aStr += aDay; + aStr += getLongDateDaySep(); + aStr += aYear; + break; + default: // YMD + aStr += aYear; + aStr += getLongDateYearSep(); + aStr += aMonth; + aStr += getLongDateMonthSep(); + aStr += aDay; + } + return aStr; +} + + +String LocaleDataWrapper::getDuration( const Time& rTime, BOOL bSec, BOOL b100Sec ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); + sal_Unicode aBuf[128]; + sal_Unicode* pBuf = aBuf; + + if ( rTime < Time( 0 ) ) + pBuf = ImplAddString( pBuf, ' ' ); + + if ( TRUE /* IsTimeLeadingZero() */ ) + pBuf = ImplAddUNum( pBuf, rTime.GetHour(), 2 ); + else + pBuf = ImplAddUNum( pBuf, rTime.GetHour() ); + pBuf = ImplAddString( pBuf, getTimeSep() ); + pBuf = ImplAdd2UNum( pBuf, rTime.GetMin(), TRUE ); + if ( bSec ) + { + pBuf = ImplAddString( pBuf, getTimeSep() ); + pBuf = ImplAdd2UNum( pBuf, rTime.GetSec(), TRUE ); + + if ( b100Sec ) + { + pBuf = ImplAddString( pBuf, getTime100SecSep() ); + pBuf = ImplAdd2UNum( pBuf, rTime.Get100Sec(), TRUE ); + } + } + + return String( aBuf, (xub_StrLen)(ULONG)(pBuf-aBuf) ); +} + + +// --- simple number formatting --------------------------------------- + +inline size_t ImplGetNumberStringLengthGuess( const LocaleDataWrapper& rLoc, USHORT nDecimals ) +{ + // approximately 3.2 bits per digit + const size_t nDig = ((sizeof(sal_Int64) * 8) / 3) + 1; + // digits, separators (pessimized for insane "every digit may be grouped"), leading zero, sign + size_t nGuess = ((nDecimals < nDig) ? + (((nDig - nDecimals) * rLoc.getNumThousandSep().Len()) + nDig) : + nDecimals) + rLoc.getNumDecimalSep().Len() + 3; + return nGuess; +} + + +String LocaleDataWrapper::getNum( sal_Int64 nNumber, USHORT nDecimals, + BOOL bUseThousandSep, BOOL bTrailingZeros ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); + sal_Unicode aBuf[128]; // big enough for 64-bit long and crazy grouping + // check if digits and separators will fit into fixed buffer or allocate + size_t nGuess = ImplGetNumberStringLengthGuess( *this, nDecimals ); + sal_Unicode* const pBuffer = (nGuess < 118 ? aBuf : + new sal_Unicode[nGuess + 16]); + + sal_Unicode* pBuf = ImplAddFormatNum( pBuffer, nNumber, nDecimals, + bUseThousandSep, bTrailingZeros ); + String aStr( pBuffer, (xub_StrLen)(ULONG)(pBuf-pBuffer) ); + + if ( pBuffer != aBuf ) + delete [] pBuffer; + return aStr; +} + + +String LocaleDataWrapper::getCurr( sal_Int64 nNumber, USHORT nDecimals, + const String& rCurrencySymbol, BOOL bUseThousandSep ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); + sal_Unicode aBuf[192]; + sal_Unicode aNumBuf[128]; // big enough for 64-bit long and crazy grouping + sal_Unicode cZeroChar = getCurrZeroChar(); + + // check if digits and separators will fit into fixed buffer or allocate + size_t nGuess = ImplGetNumberStringLengthGuess( *this, nDecimals ); + sal_Unicode* const pNumBuffer = (nGuess < 118 ? aNumBuf : + new sal_Unicode[nGuess + 16]); + + sal_Unicode* const pBuffer = + ((size_t(rCurrencySymbol.Len()) + nGuess + 20) < sizeof(aBuf)/sizeof(aBuf[0]) ? aBuf : + new sal_Unicode[ rCurrencySymbol.Len() + nGuess + 20 ]); + sal_Unicode* pBuf = pBuffer; + + BOOL bNeg; + if ( nNumber < 0 ) + { + bNeg = TRUE; + nNumber *= -1; + } + else + bNeg = FALSE; + + // convert number + sal_Unicode* pEndNumBuf = ImplAddFormatNum( pNumBuffer, nNumber, nDecimals, + bUseThousandSep, TRUE ); + xub_StrLen nNumLen = (xub_StrLen)(ULONG)(pEndNumBuf-pNumBuffer); + + // replace zeros with zero character + if ( (cZeroChar != '0') && nDecimals /* && IsNumTrailingZeros() */ ) + { + sal_Unicode* pTempBuf; + USHORT i; + BOOL bZero = TRUE; + + pTempBuf = pNumBuffer+nNumLen-nDecimals; + i = 0; + do + { + if ( *pTempBuf != '0' ) + { + bZero = FALSE; + break; + } + + pTempBuf++; + i++; + } + while ( i < nDecimals ); + + if ( bZero ) + { + pTempBuf = pNumBuffer+nNumLen-nDecimals; + i = 0; + do + { + *pTempBuf = cZeroChar; + pTempBuf++; + i++; + } + while ( i < nDecimals ); + } + } + + if ( !bNeg ) + { + switch( getCurrPositiveFormat() ) + { + case 0: + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + break; + case 1: + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + break; + case 2: + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + break; + case 3: + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + break; + } + } + else + { + switch( getCurrNegativeFormat() ) + { + case 0: + pBuf = ImplAddString( pBuf, '(' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, ')' ); + break; + case 1: + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + break; + case 2: + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + break; + case 3: + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, '-' ); + break; + case 4: + pBuf = ImplAddString( pBuf, '(' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ')' ); + break; + case 5: + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + break; + case 6: + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + break; + case 7: + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, '-' ); + break; + case 8: + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + break; + case 9: + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + break; + case 10: + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, '-' ); + break; + case 11: + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + break; + case 12: + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, '-' ); + break; + case 13: + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, '-' ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + break; + case 14: + pBuf = ImplAddString( pBuf, '(' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, ')' ); + break; + case 15: + pBuf = ImplAddString( pBuf, '(' ); + pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen ); + pBuf = ImplAddString( pBuf, ' ' ); + pBuf = ImplAddString( pBuf, rCurrencySymbol ); + pBuf = ImplAddString( pBuf, ')' ); + break; + } + } + + String aNumber( pBuffer, (xub_StrLen)(ULONG)(pBuf-pBuffer) ); + + if ( pBuffer != aBuf ) + delete [] pBuffer; + if ( pNumBuffer != aNumBuf ) + delete [] pNumBuffer; + + return aNumber; +} + + +// --- mixed ---------------------------------------------------------- + +::com::sun::star::lang::Locale LocaleDataWrapper::getLoadedLocale() const +{ + LanguageCountryInfo aLCInfo = getLanguageCountryInfo(); + return lang::Locale( aLCInfo.Language, aLCInfo.Country, aLCInfo.Variant ); +} + + +String& LocaleDataWrapper::appendLocaleInfo( String& rDebugMsg ) const +{ + ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical ); + rDebugMsg += '\n'; + rDebugMsg += String( aLocale.Language); + rDebugMsg += '_'; + rDebugMsg += String( aLocale.Country); + rDebugMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " requested\n" ) ); + lang::Locale aLoaded = getLoadedLocale(); + rDebugMsg += String( aLoaded.Language); + rDebugMsg += '_'; + rDebugMsg += String( aLoaded.Country); + rDebugMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " loaded" ) ); + return rDebugMsg; +} + + +// static +void LocaleDataWrapper::outputCheckMessage( const String& rMsg ) +{ + outputCheckMessage( ByteString( rMsg, RTL_TEXTENCODING_UTF8).GetBuffer()); +} + + +// static +void LocaleDataWrapper::outputCheckMessage( const char* pStr ) +{ + fprintf( stderr, "\n%s\n", pStr); + fflush( stderr); + DBG_ERROR( pStr); +} + + +// static +void LocaleDataWrapper::evaluateLocaleDataChecking() +{ + // Using the rtl_Instance template here wouldn't solve all threaded write + // accesses, since we want to assign the result to the static member + // variable and would need to dereference the pointer returned and assign + // the value unguarded. This is the same pattern manually coded. + BYTE nCheck = nLocaleDataChecking; + if (!nCheck) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex()); + nCheck = nLocaleDataChecking; + if (!nCheck) + { +#ifndef PRODUCT + nCheck = 1; +#else + const char* pEnv = getenv( "OOO_ENABLE_LOCALE_DATA_CHECKS"); + if (pEnv && (pEnv[0] == 'Y' || pEnv[0] == 'y' || pEnv[0] == '1')) + nCheck = 1; + else + nCheck = 2; +#endif + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + nLocaleDataChecking = nCheck; + } + } + else { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } +} diff --git a/unotools/source/i18n/makefile.mk b/unotools/source/i18n/makefile.mk new file mode 100644 index 000000000000..eab1aeb8dc48 --- /dev/null +++ b/unotools/source/i18n/makefile.mk @@ -0,0 +1,61 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.21 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=i18n + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= \ + $(SLO)$/charclass.obj \ + $(SLO)$/calendarwrapper.obj \ + $(SLO)$/collatorwrapper.obj \ + $(SLO)$/intlwrapper.obj \ + $(SLO)$/localedatawrapper.obj \ + $(SLO)$/nativenumberwrapper.obj \ + $(SLO)$/numberformatcodewrapper.obj \ + $(SLO)$/readwritemutexguard.obj \ + $(SLO)$/transliterationwrapper.obj \ + $(SLO)$/textsearch.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/i18n/nativenumberwrapper.cxx b/unotools/source/i18n/nativenumberwrapper.cxx new file mode 100644 index 000000000000..f0efd10920d7 --- /dev/null +++ b/unotools/source/i18n/nativenumberwrapper.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: nativenumberwrapper.cxx,v $ + * $Revision: 1.6 $ + * + * 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_unotools.hxx" + +#include <unotools/nativenumberwrapper.hxx> +#include <tools/debug.hxx> + +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#define LOCALEDATA_LIBRARYNAME "i18npool" +#define LOCALEDATA_SERVICENAME "com.sun.star.i18n.NativeNumberSupplier" + +using namespace ::com::sun::star; + + +NativeNumberWrapper::NativeNumberWrapper( + const uno::Reference< lang::XMultiServiceFactory > & xSF + ) + : + xSMgr( xSF ) +{ + if ( xSMgr.is() ) + { + try + { + xNNS = uno::Reference< i18n::XNativeNumberSupplier > ( xSMgr->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LOCALEDATA_SERVICENAME ) ) ), + uno::UNO_QUERY ); + } + catch ( uno::Exception& e ) + { + (void)e; + DBG_ERRORFILE( "NativeNumberWrapper ctor: Exception caught!" ); + } + } + else + { // try to get an instance somehow + DBG_ERRORFILE( "NativeNumberWrapper: no service manager, trying own" ); + try + { + uno::Reference< uno::XInterface > xI = ::comphelper::getComponentInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( LOCALEDATA_LIBRARYNAME ) ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LOCALEDATA_SERVICENAME ) ) ); + if ( xI.is() ) + { + uno::Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XNativeNumberSupplier >*)0) ); + x >>= xNNS; + } + } + catch ( uno::Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getComponentInstance: Exception caught!" ); + } + } + DBG_ASSERT( xNNS.is(), "NativeNumberWrapper: no NativeNumberSupplier" ); +} + + +NativeNumberWrapper::~NativeNumberWrapper() +{ +} + + +::rtl::OUString +NativeNumberWrapper::getNativeNumberString( + const ::rtl::OUString& rNumberString, + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nNativeNumberMode ) const +{ + try + { + if ( xNNS.is() ) + return xNNS->getNativeNumberString( rNumberString, rLocale, nNativeNumberMode ); + } + catch ( uno::Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getNativeNumberString: Exception caught!" ); + } + return ::rtl::OUString(); +} + + +sal_Bool +NativeNumberWrapper::isValidNatNum( + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nNativeNumberMode ) const +{ + try + { + if ( xNNS.is() ) + return xNNS->isValidNatNum( rLocale, nNativeNumberMode ); + } + catch ( uno::Exception& e ) + { + (void)e; + DBG_ERRORFILE( "isValidNatNum: Exception caught!" ); + } + return sal_False; +} + + +i18n::NativeNumberXmlAttributes +NativeNumberWrapper::convertToXmlAttributes( + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nNativeNumberMode ) const +{ + try + { + if ( xNNS.is() ) + return xNNS->convertToXmlAttributes( rLocale, nNativeNumberMode ); + } + catch ( uno::Exception& e ) + { + (void)e; + DBG_ERRORFILE( "convertToXmlAttributes: Exception caught!" ); + } + return i18n::NativeNumberXmlAttributes(); +} + + +sal_Int16 +NativeNumberWrapper::convertFromXmlAttributes( + const i18n::NativeNumberXmlAttributes& rAttr ) const +{ + try + { + if ( xNNS.is() ) + return xNNS->convertFromXmlAttributes( rAttr ); + } + catch ( uno::Exception& e ) + { + (void)e; + DBG_ERRORFILE( "convertFromXmlAttributes: Exception caught!" ); + } + return 0; +} + + diff --git a/unotools/source/i18n/numberformatcodewrapper.cxx b/unotools/source/i18n/numberformatcodewrapper.cxx new file mode 100644 index 000000000000..15280b345431 --- /dev/null +++ b/unotools/source/i18n/numberformatcodewrapper.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: numberformatcodewrapper.cxx,v $ + * $Revision: 1.12 $ + * + * 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_unotools.hxx" + +#include <unotools/numberformatcodewrapper.hxx> +#include <tools/debug.hxx> + +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#define LOCALEDATA_LIBRARYNAME "i18npool" +#define LOCALEDATA_SERVICENAME "com.sun.star.i18n.NumberFormatMapper" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::uno; + + +NumberFormatCodeWrapper::NumberFormatCodeWrapper( + const Reference< lang::XMultiServiceFactory > & xSF, + const lang::Locale& rLocale + ) + : + xSMgr( xSF ) +{ + setLocale( rLocale ); + if ( xSMgr.is() ) + { + try + { + xNFC = Reference< XNumberFormatCode > ( xSMgr->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LOCALEDATA_SERVICENAME ) ) ), + uno::UNO_QUERY ); + } + catch ( Exception& e ) + { + (void)e; + DBG_ERRORFILE( "NumberFormatCodeWrapper ctor: Exception caught!" ); + } + } + else + { // try to get an instance somehow + DBG_ERRORFILE( "NumberFormatCodeWrapper: no service manager, trying own" ); + try + { + Reference< XInterface > xI = ::comphelper::getComponentInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( LOCALEDATA_LIBRARYNAME ) ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LOCALEDATA_SERVICENAME ) ) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const Reference< XNumberFormatCode >*)0) ); + x >>= xNFC; + } + } + catch ( Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getComponentInstance: Exception caught!" ); + } + } + DBG_ASSERT( xNFC.is(), "NumberFormatCodeWrapper: no NumberFormatMapper" ); +} + + +NumberFormatCodeWrapper::~NumberFormatCodeWrapper() +{ +} + + +void NumberFormatCodeWrapper::setLocale( const ::com::sun::star::lang::Locale& rLocale ) +{ + aLocale = rLocale; +} + + +::com::sun::star::i18n::NumberFormatCode +NumberFormatCodeWrapper::getDefault( sal_Int16 formatType, sal_Int16 formatUsage ) const +{ + try + { + if ( xNFC.is() ) + return xNFC->getDefault( formatType, formatUsage, aLocale ); + } + catch ( Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getDefault: Exception caught!" ); + } + return ::com::sun::star::i18n::NumberFormatCode(); +} + + +::com::sun::star::i18n::NumberFormatCode +NumberFormatCodeWrapper::getFormatCode( sal_Int16 formatIndex ) const +{ + try + { + if ( xNFC.is() ) + return xNFC->getFormatCode( formatIndex, aLocale ); + } + catch ( Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getFormatCode: Exception caught!" ); + } + return ::com::sun::star::i18n::NumberFormatCode(); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode > +NumberFormatCodeWrapper::getAllFormatCode( sal_Int16 formatUsage ) const +{ + try + { + if ( xNFC.is() ) + return xNFC->getAllFormatCode( formatUsage, aLocale ); + } + catch ( Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getAllFormatCode: Exception caught!" ); + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode > (0); +} + + +::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode > +NumberFormatCodeWrapper::getAllFormatCodes() const +{ + try + { + if ( xNFC.is() ) + return xNFC->getAllFormatCodes( aLocale ); + } + catch ( Exception& e ) + { + (void)e; + DBG_ERRORFILE( "getAllFormatCodes: Exception caught!" ); + } + return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode > (0); +} diff --git a/unotools/source/i18n/readwritemutexguard.cxx b/unotools/source/i18n/readwritemutexguard.cxx new file mode 100644 index 000000000000..de614d120e5d --- /dev/null +++ b/unotools/source/i18n/readwritemutexguard.cxx @@ -0,0 +1,123 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: readwritemutexguard.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" +#include "unotools/readwritemutexguard.hxx" +#include <tools/debug.hxx> + + +namespace utl { + +ReadWriteGuard::ReadWriteGuard( ReadWriteMutex& rMutexP, + sal_Int32 nRequestMode ) + : rMutex( rMutexP ) +{ + // don't do anything until a pending write completed (or another + // ReadWriteGuard leaves the ctor phase) + ::osl::MutexGuard aGuard( rMutex.pWriteMutex ); + nMode = nRequestMode; + if ( nMode & ReadWriteGuardMode::nWrite ) + { + rMutex.pWriteMutex->acquire(); + // wait for any read to complete +// TODO: set up a waiting thread instead of a loop + sal_Bool bWait = sal_True; + do + { + rMutex.pMutex->acquire(); + bWait = (rMutex.nReadCount != 0); + if ( nMode & ReadWriteGuardMode::nCriticalChange ) + bWait |= (rMutex.nBlockCriticalCount != 0); + rMutex.pMutex->release(); + } while ( bWait ); + } + else if ( nMode & ReadWriteGuardMode::nBlockCritical ) + { + rMutex.pMutex->acquire(); + ++rMutex.nBlockCriticalCount; + rMutex.pMutex->release(); + } + else + { + rMutex.pMutex->acquire(); + ++rMutex.nReadCount; + rMutex.pMutex->release(); + } +} + + +ReadWriteGuard::~ReadWriteGuard() +{ + if ( nMode & ReadWriteGuardMode::nWrite ) + rMutex.pWriteMutex->release(); + else if ( nMode & ReadWriteGuardMode::nBlockCritical ) + { + rMutex.pMutex->acquire(); + --rMutex.nBlockCriticalCount; + rMutex.pMutex->release(); + } + else + { + rMutex.pMutex->acquire(); + --rMutex.nReadCount; + rMutex.pMutex->release(); + } +} + + +void ReadWriteGuard::changeReadToWrite() +{ + sal_Bool bOk = !(nMode & (ReadWriteGuardMode::nWrite | ReadWriteGuardMode::nBlockCritical)); + DBG_ASSERT( bOk, "ReadWriteGuard::changeReadToWrite: can't" ); + if ( bOk ) + { + // MUST release read before acquiring write mutex or dead lock would + // occur if there was a write in another thread waiting for this read + // to complete. + rMutex.pMutex->acquire(); + --rMutex.nReadCount; + rMutex.pMutex->release(); + + rMutex.pWriteMutex->acquire(); + nMode |= ReadWriteGuardMode::nWrite; + // wait for any other read to complete +// TODO: set up a waiting thread instead of a loop + sal_Bool bWait = sal_True; + do + { + rMutex.pMutex->acquire(); + bWait = (rMutex.nReadCount != 0); + rMutex.pMutex->release(); + } while ( bWait ); + } +} + +} // namespace utl diff --git a/unotools/source/i18n/textsearch.cxx b/unotools/source/i18n/textsearch.cxx new file mode 100644 index 000000000000..10909dd32307 --- /dev/null +++ b/unotools/source/i18n/textsearch.cxx @@ -0,0 +1,401 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textsearch.cxx,v $ + * $Revision: 1.18 $ + * + * 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_unotools.hxx" +#include <i18npool/mslangid.hxx> +#include <tools/debug.hxx> +#ifndef _INTN_HXX //autogen +//#include <tools/intn.hxx> +#endif +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#ifndef _COM_SUN_STAR_UTIL_SEARCHFLAGS_HDL_ +#include <com/sun/star/util/SearchFlags.hdl> +#endif +#include <com/sun/star/i18n/TransliterationModules.hpp> +#include <unotools/charclass.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/textsearch.hxx> + +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// ............................................................................ +namespace utl +{ +// ............................................................................ + +SearchParam::SearchParam( const String &rText, + SearchType eType, + BOOL bCaseSensitive, + BOOL bWrdOnly, + BOOL bSearchInSel ) +{ + sSrchStr = rText; + eSrchType = eType; + + bWordOnly = bWrdOnly; + bSrchInSel = bSearchInSel; + bCaseSense = bCaseSensitive; + + nTransliterationFlags = 0; + + // Werte fuer "Gewichtete Levenshtein-Distanz" + bLEV_Relaxed = TRUE; + nLEV_OtherX = 2; + nLEV_ShorterY = 1; + nLEV_LongerZ = 3; +} + +SearchParam::SearchParam( const SearchParam& rParam ) +{ + sSrchStr = rParam.sSrchStr; + sReplaceStr = rParam.sReplaceStr; + eSrchType = rParam.eSrchType; + + bWordOnly = rParam.bWordOnly; + bSrchInSel = rParam.bSrchInSel; + bCaseSense = rParam.bCaseSense; + + bLEV_Relaxed = rParam.bLEV_Relaxed; + nLEV_OtherX = rParam.nLEV_OtherX; + nLEV_ShorterY = rParam.nLEV_ShorterY; + nLEV_LongerZ = rParam.nLEV_LongerZ; + + nTransliterationFlags = rParam.nTransliterationFlags; +} + +// Klasse zum Suchen eines Strings in einem Text. Es wird genau nach +// dem String gesucht. +// ( Die Unterscheidung der Gross/Klein-Schreibung kann mit einen Flag +// unterdrueckt werden ) + +TextSearch::CachedTextSearch TextSearch::maCache; + +static bool lcl_Equals( const SearchOptions& rSO1, const SearchOptions& rSO2 ) +{ + return rSO1.algorithmType == rSO2.algorithmType && + rSO1.searchFlag == rSO2.searchFlag && + rSO1.searchString.equals(rSO2.searchString) && + rSO1.replaceString.equals(rSO2.replaceString) && + rSO1.changedChars == rSO2.changedChars && + rSO1.deletedChars == rSO2.deletedChars && + rSO1.insertedChars == rSO2.insertedChars && + rSO1.Locale.Language == rSO2.Locale.Language && + rSO1.Locale.Country == rSO2.Locale.Country && + rSO1.Locale.Variant == rSO2.Locale.Variant && + rSO1.transliterateFlags == rSO2.transliterateFlags; +} + +Reference<XTextSearch> TextSearch::getXTextSearch( const SearchOptions& rPara ) +{ + osl::MutexGuard aGuard(maCache.mutex); + + if ( lcl_Equals(maCache.Options, rPara) ) + return maCache.xTextSearch; + + try + { + Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + maCache.xTextSearch.set( xMSF->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.util.TextSearch" ) ) ), UNO_QUERY_THROW ); + maCache.xTextSearch->setOptions( rPara ); + maCache.Options = rPara; + } + catch ( Exception& ) + { + DBG_ERRORFILE( "TextSearch ctor: Exception caught!" ); + } + return maCache.xTextSearch; +} + +TextSearch::TextSearch(const SearchParam & rParam, LanguageType eLang ) +{ + if( LANGUAGE_NONE == eLang ) + eLang = LANGUAGE_SYSTEM; + ::com::sun::star::lang::Locale aLocale( + MsLangId::convertLanguageToLocale( LanguageType(eLang))); + + Init( rParam, aLocale); +} + +TextSearch::TextSearch(const SearchParam & rParam, const CharClass& rCClass ) +{ + Init( rParam, rCClass.getLocale() ); +} + +TextSearch::TextSearch( const SearchOptions& rPara ) +{ + xTextSearch = getXTextSearch( rPara ); +} + +void TextSearch::Init( const SearchParam & rParam, + const ::com::sun::star::lang::Locale& rLocale ) +{ + // convert SearchParam to the UNO SearchOptions + SearchOptions aSOpt; + + switch( rParam.GetSrchType() ) + { + case SearchParam::SRCH_REGEXP: + aSOpt.algorithmType = SearchAlgorithms_REGEXP; + if( rParam.IsSrchInSelection() ) + aSOpt.searchFlag |= SearchFlags::REG_NOT_BEGINOFLINE | + SearchFlags::REG_NOT_ENDOFLINE; + break; + + case SearchParam::SRCH_LEVDIST: + aSOpt.algorithmType = SearchAlgorithms_APPROXIMATE; + aSOpt.changedChars = rParam.GetLEVOther(); + aSOpt.deletedChars = rParam.GetLEVLonger(); + aSOpt.insertedChars = rParam.GetLEVShorter(); + if( rParam.IsSrchRelaxed() ) + aSOpt.searchFlag |= SearchFlags::LEV_RELAXED; + break; + +// case SearchParam::SRCH_NORMAL: + default: + aSOpt.algorithmType = SearchAlgorithms_ABSOLUTE; + if( rParam.IsSrchWordOnly() ) + aSOpt.searchFlag |= SearchFlags::NORM_WORD_ONLY; + break; + } + aSOpt.searchString = rParam.GetSrchStr(); + aSOpt.replaceString = rParam.GetReplaceStr(); + aSOpt.Locale = rLocale; + aSOpt.transliterateFlags = rParam.GetTransliterationFlags(); + if( !rParam.IsCaseSensitive() ) + { + aSOpt.searchFlag |= SearchFlags::ALL_IGNORE_CASE; + aSOpt.transliterateFlags |= ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE; + } + + xTextSearch = getXTextSearch( aSOpt ); +} + +void TextSearch::SetLocale( const ::com::sun::star::util::SearchOptions& rOptions, + const ::com::sun::star::lang::Locale& rLocale ) +{ + // convert SearchParam to the UNO SearchOptions + SearchOptions aSOpt( rOptions ); + aSOpt.Locale = rLocale; + + xTextSearch = getXTextSearch( aSOpt ); +} + + +TextSearch::~TextSearch() +{ +} + +/* + * Die allgemeinen Methoden zu Suchen. Diese rufen dann die entpsrecheden + * Methoden fuer die normale Suche oder der Suche nach Regular-Expressions + * ueber die MethodenPointer auf. + */ +#if defined _MSC_VER +#pragma optimize("", off) +#pragma warning(push) +#pragma warning(disable: 4748) +#endif +int TextSearch::SearchFrwrd( const String & rStr, xub_StrLen* pStart, + xub_StrLen* pEnde, SearchResult* pRes ) +{ + int nRet = 0; + try + { + if( xTextSearch.is() ) + { + SearchResult aRet( xTextSearch->searchForward( + rStr, *pStart, *pEnde )); + if( aRet.subRegExpressions > 0 ) + { + nRet = 1; + // the XTextsearch returns in startOffset the higher position + // and the endposition is allways exclusive. + // The caller of this function will have in startPos the + // lower pos. and end + *pStart = (xub_StrLen)aRet.startOffset[ 0 ]; + *pEnde = (xub_StrLen)aRet.endOffset[ 0 ]; + if( pRes ) + *pRes = aRet; + } + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "SearchForward: Exception caught!" ); + } + return nRet; +} + +int TextSearch::SearchBkwrd( const String & rStr, xub_StrLen* pStart, + xub_StrLen* pEnde, SearchResult* pRes ) +{ + int nRet = 0; + try + { + if( xTextSearch.is() ) + { + SearchResult aRet( xTextSearch->searchBackward( + rStr, *pStart, *pEnde )); + if( aRet.subRegExpressions ) + { + nRet = 1; + // the XTextsearch returns in startOffset the higher position + // and the endposition is allways exclusive. + // The caller of this function will have in startPos the + // lower pos. and end + *pEnde = (xub_StrLen)aRet.startOffset[ 0 ]; + *pStart = (xub_StrLen)aRet.endOffset[ 0 ]; + if( pRes ) + *pRes = aRet; + } + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "SearchBackward: Exception caught!" ); + } + return nRet; +} + +void TextSearch::ReplaceBackReferences( String& rReplaceStr, const String &rStr, const SearchResult& rResult ) +{ + if( rResult.subRegExpressions > 0 ) + { + String sTab( '\t' ); + sal_Unicode sSrchChrs[] = {'\\', '&', '$', 0}; + String sTmp; + xub_StrLen nPos = 0; + sal_Unicode sFndChar; + while( STRING_NOTFOUND != ( nPos = rReplaceStr.SearchChar( sSrchChrs, nPos )) ) + { + if( rReplaceStr.GetChar( nPos ) == '&') + { + USHORT nStart = (USHORT)(rResult.startOffset[0]); + USHORT nLength = (USHORT)(rResult.endOffset[0] - rResult.startOffset[0]); + rReplaceStr.Erase( nPos, 1 ); // delete ampersand + // replace by found string + rReplaceStr.Insert( rStr, nStart, nLength, nPos ); + // jump over + nPos = nPos + nLength; + } + else if( rReplaceStr.GetChar( nPos ) == '$') + { + if( nPos + 1 < rReplaceStr.Len()) + { + sFndChar = rReplaceStr.GetChar( nPos + 1 ); + switch(sFndChar) + { // placeholder for a backward reference? + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + rReplaceStr.Erase( nPos, 2 ); // delete both + int i = sFndChar - '0'; // index + if(i < rResult.subRegExpressions) + { + USHORT nSttReg = (USHORT)(rResult.startOffset[i]); + USHORT nRegLen = (USHORT)(rResult.endOffset[i]); + if( nRegLen > nSttReg ) + nRegLen = nRegLen - nSttReg; + else + { + nRegLen = nSttReg - nRegLen; + nSttReg = (USHORT)(rResult.endOffset[i]); + } + // Copy reference from found string + sTmp = rStr.Copy((USHORT)nSttReg, (USHORT)nRegLen); + // insert + rReplaceStr.Insert( sTmp, nPos ); + // and step over + nPos = nPos + sTmp.Len(); + } + } + break; + default: + nPos += 2; // leave both chars unchanged + break; + } + } + else + ++nPos; + } + else + { + // at least another character? + if( nPos + 1 < rReplaceStr.Len()) + { + sFndChar = rReplaceStr.GetChar( nPos + 1 ); + switch(sFndChar) + { + case '\\': + case '&': + case '$': + rReplaceStr.Erase( nPos, 1 ); + nPos++; + break; + case 't': + rReplaceStr.Erase( nPos, 2 ); // delete both + rReplaceStr.Insert( sTab, nPos ); // insert tabulator + nPos++; // step over + break; + default: + nPos += 2; // ignore both characters + break; + } + } + else + ++nPos; + } + } + } +} + + +#if defined _MSC_VER +#pragma optimize("", on) +#pragma warning(pop) +#endif + +// ............................................................................ +} // namespace utl +// ............................................................................ + diff --git a/unotools/source/i18n/transliterationwrapper.cxx b/unotools/source/i18n/transliterationwrapper.cxx new file mode 100644 index 000000000000..bd33e447471f --- /dev/null +++ b/unotools/source/i18n/transliterationwrapper.cxx @@ -0,0 +1,326 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: transliterationwrapper.cxx,v $ + * $Revision: 1.17 $ + * + * 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_unotools.hxx" + +#include <unotools/transliterationwrapper.hxx> +#include <tools/debug.hxx> +#include <i18npool/mslangid.hxx> +#ifndef _COMPHELPER_COMPONENTFACTORY_HXX_ +#include <comphelper/componentfactory.hxx> +#endif +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#define TRANSLIT_LIBRARYNAME "i18n" +#define TRANSLIT_SERVICENAME "com.sun.star.i18n.Transliteration" + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::uno; +using namespace ::utl; + +TransliterationWrapper::TransliterationWrapper( + const Reference< XMultiServiceFactory > & xSF, + sal_uInt32 nTyp ) + : xSMgr( xSF ), nType( nTyp ), nLanguage( 0 ), bFirstCall( sal_True ) +{ + if( xSMgr.is() ) + { + try { + xTrans = Reference< XExtendedTransliteration > ( + xSMgr->createInstance( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + TRANSLIT_SERVICENAME))), UNO_QUERY ); + } + catch ( Exception& ) + { + DBG_ERRORFILE( "TransliterationWrapper: Exception caught!" ); + } + } + else + { // try to get an instance somehow + DBG_ERRORFILE( "TransliterationWrapper: no service manager, trying own" ); + try + { + Reference< XInterface > xI = ::comphelper::getComponentInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( LLCF_LIBNAME( + TRANSLIT_LIBRARYNAME ))), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + TRANSLIT_SERVICENAME))); + if ( xI.is() ) + { + Any x = xI->queryInterface( + ::getCppuType((const Reference< XExtendedTransliteration>*)0) ); + x >>= xTrans ; + } + } + catch ( Exception& ) + { + DBG_ERRORFILE( "getComponentInstance: Exception caught!" ); + } + } + DBG_ASSERT( xTrans.is(), "TransliterationWrapper: no Transliteraion available" ); +} + + +TransliterationWrapper::~TransliterationWrapper() +{ +} + + +String TransliterationWrapper::transliterate( + const String& rStr, sal_uInt16 nLang, + xub_StrLen nStart, xub_StrLen nLen, + Sequence <sal_Int32>* pOffset ) +{ + String sRet; + if( xTrans.is() ) + { + try + { + loadModuleIfNeeded( nLang ); + + if ( pOffset ) + sRet = xTrans->transliterate( rStr, nStart, nLen, *pOffset ); + else + sRet = xTrans->transliterateString2String( rStr, nStart, nLen); + } + catch( Exception& ) + { + DBG_ERRORFILE( "transliterate: Exception caught!" ); + } + } + return sRet; +} + + +String TransliterationWrapper::transliterate( + const String& rStr, + xub_StrLen nStart, xub_StrLen nLen, + Sequence <sal_Int32>* pOffset ) const +{ + String sRet( rStr ); + if( xTrans.is() ) + { + try + { + if ( pOffset ) + sRet = xTrans->transliterate( rStr, nStart, nLen, *pOffset ); + else + sRet = xTrans->transliterateString2String( rStr, nStart, nLen); + } + catch( Exception& ) + { + DBG_ERRORFILE( "transliterate: Exception caught!" ); + } + } + return sRet; +} + +sal_Bool TransliterationWrapper::needLanguageForTheMode() const +{ + return TransliterationModules_UPPERCASE_LOWERCASE == nType || + TransliterationModules_LOWERCASE_UPPERCASE == nType || + TransliterationModules_IGNORE_CASE == nType; +} + + +void TransliterationWrapper::setLanguageLocaleImpl( sal_uInt16 nLang ) +{ + nLanguage = nLang; + if( LANGUAGE_NONE == nLanguage ) + nLanguage = LANGUAGE_SYSTEM; + MsLangId::convertLanguageToLocale( nLanguage, aLocale); +} + + +void TransliterationWrapper::loadModuleIfNeeded( sal_uInt16 nLang ) +{ + sal_Bool bLoad = bFirstCall; + bFirstCall = sal_False; + + if( nLanguage != nLang ) + { + setLanguageLocaleImpl( nLang ); + if( !bLoad ) + bLoad = needLanguageForTheMode(); + } + if( bLoad ) + loadModuleImpl(); +} + + +void TransliterationWrapper::loadModuleImpl() const +{ + if ( bFirstCall ) + ((TransliterationWrapper*)this)->setLanguageLocaleImpl( LANGUAGE_SYSTEM ); + + try + { + if ( xTrans.is() ) + xTrans->loadModule( (TransliterationModules)nType, aLocale ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "loadModuleImpl: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + + bFirstCall = sal_False; +} + + +void TransliterationWrapper::loadModuleByImplName( + const String& rModuleName, sal_uInt16 nLang ) +{ + try + { + setLanguageLocaleImpl( nLang ); + // Reset LanguageType, so the next call to loadModuleIfNeeded() forces + // new settings. + nLanguage = LANGUAGE_DONTKNOW; + if ( xTrans.is() ) + xTrans->loadModuleByImplName( rModuleName, aLocale ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "loadModuleByImplName: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + + bFirstCall = sal_False; +} + + +sal_Bool TransliterationWrapper::equals( + const String& rStr1, sal_Int32 nPos1, sal_Int32 nCount1, sal_Int32& nMatch1, + const String& rStr2, sal_Int32 nPos2, sal_Int32 nCount2, sal_Int32& nMatch2 ) const +{ + try + { + if( bFirstCall ) + loadModuleImpl(); + if ( xTrans.is() ) + return xTrans->equals( rStr1, nPos1, nCount1, nMatch1, rStr2, nPos2, nCount2, nMatch2 ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "equals: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return sal_False; +} + + +sal_Int32 TransliterationWrapper::compareSubstring( + const String& rStr1, sal_Int32 nOff1, sal_Int32 nLen1, + const String& rStr2, sal_Int32 nOff2, sal_Int32 nLen2 ) const +{ + try + { + if( bFirstCall ) + loadModuleImpl(); + if ( xTrans.is() ) + return xTrans->compareSubstring( rStr1, nOff1, nLen1, rStr2, nOff2, nLen2 ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "compareSubstring: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +sal_Int32 TransliterationWrapper::compareString( const String& rStr1, const String& rStr2 ) const +{ + try + { + if( bFirstCall ) + loadModuleImpl(); + if ( xTrans.is() ) + return xTrans->compareString( rStr1, rStr2 ); + } + catch ( Exception& e ) + { +#ifndef PRODUCT + ByteString aMsg( "compareString: Exception caught\n" ); + aMsg += ByteString( String( e.Message ), RTL_TEXTENCODING_UTF8 ); + DBG_ERRORFILE( aMsg.GetBuffer() ); +#else + (void)e; +#endif + } + return 0; +} + + +// --- helpers -------------------------------------------------------- + +sal_Bool TransliterationWrapper::isEqual( const String& rStr1, const String& rStr2 ) const +{ + sal_Int32 nMatch1, nMatch2; + sal_Bool bMatch = equals( + rStr1, 0, rStr1.Len(), nMatch1, + rStr2, 0, rStr2.Len(), nMatch2 ); + return bMatch; +} + + +sal_Bool TransliterationWrapper::isMatch( const String& rStr1, const String& rStr2 ) const +{ + sal_Int32 nMatch1, nMatch2; + equals( + rStr1, 0, rStr1.Len(), nMatch1, + rStr2, 0, rStr2.Len(), nMatch2 ); + return (nMatch1 <= nMatch2) && (nMatch1 == rStr1.Len()); +} diff --git a/unotools/source/misc/atom.cxx b/unotools/source/misc/atom.cxx new file mode 100644 index 000000000000..03a459326d08 --- /dev/null +++ b/unotools/source/misc/atom.cxx @@ -0,0 +1,386 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: atom.cxx,v $ + * $Revision: 1.10 $ + * + * 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_unotools.hxx" + +#include <unotools/atom.hxx> + +using namespace utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +#define NMSP_UTIL ::com::sun::star::util + +AtomProvider::AtomProvider() +{ + m_nAtoms = 1; +} + +AtomProvider::~AtomProvider() +{ +} + +int AtomProvider::getAtom( const ::rtl::OUString& rString, sal_Bool bCreate ) +{ + ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::iterator it = m_aAtomMap.find( rString ); + if( it != m_aAtomMap.end() ) + return it->second; + if( ! bCreate ) + return INVALID_ATOM; + m_aAtomMap[ rString ] = m_nAtoms; + m_aStringMap[ m_nAtoms ] = rString; + m_nAtoms++; + return m_nAtoms-1; +} + +void AtomProvider::getAll( ::std::list< ::utl::AtomDescription >& atoms ) +{ + atoms.clear(); + ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::const_iterator it = m_aAtomMap.begin(); + + ::utl::AtomDescription aDesc; + while( it != m_aAtomMap.end() ) + { + aDesc.atom = it->second; + aDesc.description = it->first; + atoms.push_back( aDesc ); + ++it; + } +} + +void AtomProvider::getRecent( int atom, ::std::list< ::utl::AtomDescription >& atoms ) +{ + atoms.clear(); + + ::std::hash_map< ::rtl::OUString, int, ::rtl::OUStringHash >::const_iterator it = m_aAtomMap.begin(); + + ::utl::AtomDescription aDesc; + while( it != m_aAtomMap.end() ) + { + if( it->second > atom ) + { + aDesc.atom = it->second; + aDesc.description = it->first; + atoms.push_back( aDesc ); + } + ++it; + } +} + +const ::rtl::OUString& AtomProvider::getString( int nAtom ) const +{ + static ::rtl::OUString aEmpty; + ::std::hash_map< int, ::rtl::OUString, ::std::hash< int > >::const_iterator it = m_aStringMap.find( nAtom ); + + return it == m_aStringMap.end() ? aEmpty : it->second; +} + +void AtomProvider::overrideAtom( int atom, const ::rtl::OUString& description ) +{ + m_aAtomMap[ description ] = atom; + m_aStringMap[ atom ] = description; + if( m_nAtoms <= atom ) + m_nAtoms=atom+1; +} + +sal_Bool AtomProvider::hasAtom( int atom ) const +{ + return m_aStringMap.find( atom ) != m_aStringMap.end() ? sal_True : sal_False; +} + +// ----------------------------------------------------------------------- + +MultiAtomProvider::MultiAtomProvider() +{ +} + +MultiAtomProvider::~MultiAtomProvider() +{ + for( ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it = m_aAtomLists.begin(); it != m_aAtomLists.end(); ++it ) + delete it->second; +} + + +sal_Bool MultiAtomProvider::insertAtomClass( int atomClass ) +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it = + m_aAtomLists.find( atomClass ); + if( it != m_aAtomLists.end() ) + return sal_False; + m_aAtomLists[ atomClass ] = new AtomProvider(); + return sal_True; +} + +int MultiAtomProvider::getAtom( int atomClass, const ::rtl::OUString& rString, sal_Bool bCreate ) +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::iterator it = + m_aAtomLists.find( atomClass ); + if( it != m_aAtomLists.end() ) + return it->second->getAtom( rString, bCreate ); + + if( bCreate ) + { + AtomProvider* pNewClass; + m_aAtomLists[ atomClass ] = pNewClass = new AtomProvider(); + return pNewClass->getAtom( rString, bCreate ); + } + return INVALID_ATOM; +} + +int MultiAtomProvider::getLastAtom( int atomClass ) const +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = + m_aAtomLists.find( atomClass ); + + return it != m_aAtomLists.end() ? it->second->getLastAtom() : INVALID_ATOM; +} + +void MultiAtomProvider::getRecent( int atomClass, int atom, ::std::list< ::utl::AtomDescription >& atoms ) +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = + m_aAtomLists.find( atomClass ); + if( it != m_aAtomLists.end() ) + it->second->getRecent( atom, atoms ); + else + atoms.clear(); +} + +const ::rtl::OUString& MultiAtomProvider::getString( int atomClass, int atom ) const +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = + m_aAtomLists.find( atomClass ); + if( it != m_aAtomLists.end() ) + return it->second->getString( atom ); + + static ::rtl::OUString aEmpty; + return aEmpty; +} + +sal_Bool MultiAtomProvider::hasAtom( int atomClass, int atom ) const +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass ); + return it != m_aAtomLists.end() ? it->second->hasAtom( atom ) : sal_False; +} + +void MultiAtomProvider::getClass( int atomClass, ::std::list< ::utl::AtomDescription >& atoms) const +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass ); + + if( it != m_aAtomLists.end() ) + it->second->getAll( atoms ); + else + atoms.clear(); +} + +void MultiAtomProvider::overrideAtom( int atomClass, int atom, const ::rtl::OUString& description ) +{ + ::std::hash_map< int, AtomProvider*, ::std::hash< int > >::const_iterator it = m_aAtomLists.find( atomClass ); + if( it == m_aAtomLists.end() ) + m_aAtomLists[ atomClass ] = new AtomProvider(); + m_aAtomLists[ atomClass ]->overrideAtom( atom, description ); +} + +// ----------------------------------------------------------------------- + +AtomServer::AtomServer() +{ +} + +AtomServer::~AtomServer() +{ +} + +sal_Int32 AtomServer::getAtom( sal_Int32 atomClass, const ::rtl::OUString& description, sal_Bool create ) throw() +{ + ::osl::Guard< ::osl::Mutex > guard( m_aMutex ); + + return m_aProvider.getAtom( atomClass, description, create ); +} + +Sequence< Sequence< NMSP_UTIL::AtomDescription > > AtomServer::getClasses( const Sequence< sal_Int32 >& atomClasses ) throw() +{ + ::osl::Guard< ::osl::Mutex > guard( m_aMutex ); + + Sequence< Sequence< NMSP_UTIL::AtomDescription > > aRet( atomClasses.getLength() ); + for( int i = 0; i < atomClasses.getLength(); i++ ) + { + aRet.getArray()[i] = getClass( atomClasses.getConstArray()[i] ); + } + return aRet; +} + +Sequence< NMSP_UTIL::AtomDescription > AtomServer::getClass( sal_Int32 atomClass ) throw() +{ + ::osl::Guard< ::osl::Mutex > guard( m_aMutex ); + + ::std::list< ::utl::AtomDescription > atoms; + m_aProvider.getClass( atomClass, atoms ); + + Sequence< NMSP_UTIL::AtomDescription > aRet( atoms.size() ); + for( int i = aRet.getLength()-1; i >= 0; i-- ) + { + aRet.getArray()[i].atom = atoms.back().atom; + aRet.getArray()[i].description = atoms.back().description; + atoms.pop_back(); + } + + return aRet; +} + +Sequence< NMSP_UTIL::AtomDescription > AtomServer::getRecentAtoms( sal_Int32 atomClass, sal_Int32 atom ) throw() +{ + ::osl::Guard< ::osl::Mutex > guard( m_aMutex ); + + ::std::list< ::utl::AtomDescription > atoms; + m_aProvider.getRecent( atomClass, atom, atoms ); + + Sequence< NMSP_UTIL::AtomDescription > aRet( atoms.size() ); + for( int i = aRet.getLength()-1; i >= 0; i-- ) + { + aRet.getArray()[i].atom = atoms.back().atom; + aRet.getArray()[i].description = atoms.back().description; + atoms.pop_back(); + } + + return aRet; +} + +Sequence< ::rtl::OUString > AtomServer::getAtomDescriptions( const Sequence< AtomClassRequest >& atoms ) throw() +{ + ::osl::Guard< ::osl::Mutex > guard( m_aMutex ); + + int nStrings = 0, i; + for( i = 0; i < atoms.getLength(); i++ ) + nStrings += atoms.getConstArray()[ i ].atoms.getLength(); + Sequence< ::rtl::OUString > aRet( nStrings ); + for( i = 0, nStrings = 0; i < atoms.getLength(); i++ ) + { + const AtomClassRequest& rRequest = atoms.getConstArray()[i]; + for( int n = 0; n < rRequest.atoms.getLength(); n++ ) + aRet.getArray()[ nStrings++ ] = m_aProvider.getString( rRequest.atomClass, rRequest.atoms.getConstArray()[ n ] ); + } + return aRet; +} + +// ----------------------------------------------------------------------- + +AtomClient::AtomClient( const Reference< XAtomServer >& xServer ) : + m_xServer( xServer ) +{ +} + +AtomClient::~AtomClient() +{ +} + +int AtomClient::getAtom( int atomClass, const ::rtl::OUString& description, sal_Bool bCreate ) +{ + int nAtom = m_aProvider.getAtom( atomClass, description, sal_False ); + if( nAtom == INVALID_ATOM && bCreate ) + { + try + { + nAtom = m_xServer->getAtom( atomClass, description, bCreate ); + } + catch( RuntimeException& ) + { + return INVALID_ATOM; + } + if( nAtom != INVALID_ATOM ) + m_aProvider.overrideAtom( atomClass, nAtom, description ); + } + return nAtom; +} + +const ::rtl::OUString& AtomClient::getString( int atomClass, int atom ) +{ + static ::rtl::OUString aEmpty; + + if( ! m_aProvider.hasAtom( atomClass, atom ) ) + { + Sequence< NMSP_UTIL::AtomDescription > aSeq; + try + { + aSeq = m_xServer->getRecentAtoms( atomClass, m_aProvider.getLastAtom( atomClass ) ); + } + catch( RuntimeException& ) + { + return aEmpty; + } + const NMSP_UTIL::AtomDescription* pDescriptions = aSeq.getConstArray(); + for( int i = 0; i < aSeq.getLength(); i++ ) + m_aProvider.overrideAtom( atomClass, + pDescriptions[i].atom, + pDescriptions[i].description + ); + + if( ! m_aProvider.hasAtom( atomClass, atom ) ) + { + // holes may occur by the above procedure! + Sequence< AtomClassRequest > aReq( 1 ); + aReq.getArray()[0].atomClass = atomClass; + aReq.getArray()[0].atoms.realloc( 1 ); + aReq.getArray()[0].atoms.getArray()[0] = atom; + Sequence< ::rtl::OUString > aRet; + try + { + aRet = m_xServer->getAtomDescriptions( aReq ); + } + catch( RuntimeException& ) + { + return aEmpty; + } + if( aRet.getLength() == 1 ) + m_aProvider.overrideAtom( atomClass, atom, aRet.getConstArray()[0] ); + } + } + return m_aProvider.getString( atomClass, atom ); +} + +void AtomClient::updateAtomClasses( const Sequence< sal_Int32 >& atomClasses ) +{ + Sequence< Sequence< NMSP_UTIL::AtomDescription > > aUpdate; + try + { + aUpdate = m_xServer->getClasses( atomClasses ); + } + catch( RuntimeException& ) + { + return; + } + for( int i = 0; i < atomClasses.getLength(); i++ ) + { + int nClass = atomClasses.getConstArray()[i]; + const Sequence< NMSP_UTIL::AtomDescription >& rClass = aUpdate.getConstArray()[i]; + const NMSP_UTIL::AtomDescription* pDesc = rClass.getConstArray(); + for( int n = 0; n < rClass.getLength(); n++, pDesc++ ) + m_aProvider.overrideAtom( nClass, pDesc->atom, pDesc->description ); + } +} diff --git a/unotools/source/misc/componentresmodule.cxx b/unotools/source/misc/componentresmodule.cxx new file mode 100644 index 000000000000..9f0eaa055da8 --- /dev/null +++ b/unotools/source/misc/componentresmodule.cxx @@ -0,0 +1,149 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: componentresmodule.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" +#include <unotools/componentresmodule.hxx> + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ +#include <tools/resmgr.hxx> +#include <osl/diagnose.h> + +//........................................................................ +namespace utl +{ +//........................................................................ + + //==================================================================== + //= OComponentResModuleImpl + //==================================================================== + /** PIMPL-class for OComponentResourceModule + + not threadsafe! + */ + class OComponentResModuleImpl + { + private: + ResMgr* m_pRessources; + bool m_bInitialized; + ::rtl::OString m_sResFilePrefix; + + public: + OComponentResModuleImpl( const ::rtl::OString& _rResFilePrefix ) + :m_pRessources( NULL ) + ,m_bInitialized( false ) + ,m_sResFilePrefix( _rResFilePrefix ) + { + } + + ~OComponentResModuleImpl() + { + freeResManager(); + } + + /** releases our resource manager + */ + void freeResManager(); + + /** retrieves our resource manager + */ + ResMgr* getResManager(); + + private: + OComponentResModuleImpl(); // never implemented + OComponentResModuleImpl( const OComponentResModuleImpl& ); // never implemented + OComponentResModuleImpl& operator=( const OComponentResModuleImpl& ); // never implemented + }; + + //-------------------------------------------------------------------- + void OComponentResModuleImpl::freeResManager() + { + delete m_pRessources, m_pRessources = NULL; + m_bInitialized = false; + } + + //-------------------------------------------------------------------- + ResMgr* OComponentResModuleImpl::getResManager() + { + if ( !m_pRessources && !m_bInitialized ) + { + // create a manager with a fixed prefix + ByteString aMgrName = m_sResFilePrefix; + + m_pRessources = ResMgr::CreateResMgr( aMgrName.GetBuffer() ); + OSL_ENSURE( m_pRessources, + ( ByteString( "OModuleImpl::getResManager: could not create the resource manager (file name: " ) + += aMgrName + += ByteString( ")!" ) ).GetBuffer() ); + + m_bInitialized = sal_True; + } + return m_pRessources; + } + + //==================================================================== + //= OComponentResourceModule + //==================================================================== + //-------------------------------------------------------------------- + OComponentResourceModule::OComponentResourceModule( const ::rtl::OString& _rResFilePrefix ) + :BaseClass() + ,m_pImpl( new OComponentResModuleImpl( _rResFilePrefix ) ) + { + } + + //-------------------------------------------------------------------- + OComponentResourceModule::~OComponentResourceModule() + { + } + + //------------------------------------------------------------------------- + ResMgr* OComponentResourceModule::getResManager() + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_pImpl->getResManager(); + } + + //-------------------------------------------------------------------------- + void OComponentResourceModule::onFirstClient() + { + BaseClass::onFirstClient(); + } + + //-------------------------------------------------------------------------- + void OComponentResourceModule::onLastClient() + { + m_pImpl->freeResManager(); + BaseClass::onLastClient(); + } + +//........................................................................ +} // namespace utl +//........................................................................ diff --git a/unotools/source/misc/datetime.cxx b/unotools/source/misc/datetime.cxx new file mode 100644 index 000000000000..cab276309542 --- /dev/null +++ b/unotools/source/misc/datetime.cxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: datetime.cxx,v $ + * $Revision: 1.4 $ + * + * 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_unotools.hxx" +#include <unotools/datetime.hxx> +#include <tools/date.hxx> +#include <tools/time.hxx> +#include <tools/datetime.hxx> + +//......................................................................... +namespace utl +{ +//......................................................................... + +//------------------------------------------------------------------ +void typeConvert(const Time& _rTime, starutil::Time& _rOut) +{ + _rOut.Hours = _rTime.GetHour(); + _rOut.Minutes = _rTime.GetMin(); + _rOut.Seconds = _rTime.GetSec(); + _rOut.HundredthSeconds = _rTime.Get100Sec(); +} + +//------------------------------------------------------------------ +void typeConvert(const starutil::Time& _rTime, Time& _rOut) +{ + _rOut = Time(_rTime.Hours, _rTime.Minutes, _rTime.Seconds, _rTime.HundredthSeconds); +} + +//------------------------------------------------------------------ +void typeConvert(const Date& _rDate, starutil::Date& _rOut) +{ + _rOut.Day = _rDate.GetDay(); + _rOut.Month = _rDate.GetMonth(); + _rOut.Year = _rDate.GetYear(); +} + +//------------------------------------------------------------------ +void typeConvert(const starutil::Date& _rDate, Date& _rOut) +{ + _rOut = Date(_rDate.Day, _rDate.Month, _rDate.Year); +} + +//------------------------------------------------------------------ +void typeConvert(const DateTime& _rDateTime, starutil::DateTime& _rOut) +{ + _rOut.Year = _rDateTime.GetYear(); + _rOut.Month = _rDateTime.GetMonth(); + _rOut.Day = _rDateTime.GetDay(); + _rOut.Hours = _rDateTime.GetHour(); + _rOut.Minutes = _rDateTime.GetMin(); + _rOut.Seconds = _rDateTime.GetSec(); + _rOut.HundredthSeconds = _rDateTime.Get100Sec(); +} + +//------------------------------------------------------------------ +void typeConvert(const starutil::DateTime& _rDateTime, DateTime& _rOut) +{ + Date aDate(_rDateTime.Day, _rDateTime.Month, _rDateTime.Year); + Time aTime(_rDateTime.Hours, _rDateTime.Minutes, _rDateTime.Seconds, _rDateTime.HundredthSeconds); + _rOut = DateTime(aDate, aTime); +} + +//------------------------------------------------------------------------- +sal_Bool operator ==(const starutil::DateTime& _rLeft, const starutil::DateTime& _rRight) +{ + return ( _rLeft.HundredthSeconds == _rRight.HundredthSeconds) && + ( _rLeft.Seconds == _rRight.Seconds) && + ( _rLeft.Minutes == _rRight.Minutes) && + ( _rLeft.Hours == _rRight.Hours) && + ( _rLeft.Day == _rRight.Day) && + ( _rLeft.Month == _rRight.Month) && + ( _rLeft.Year == _rRight.Year) ; +} + +//------------------------------------------------------------------------- +sal_Bool operator ==(const starutil::Date& _rLeft, const starutil::Date& _rRight) +{ + return ( _rLeft.Day == _rRight.Day) && + ( _rLeft.Month == _rRight.Month) && + ( _rLeft.Year == _rRight.Year) ; +} + +//------------------------------------------------------------------------- +sal_Bool operator ==(const starutil::Time& _rLeft, const starutil::Time& _rRight) +{ + return ( _rLeft.HundredthSeconds == _rRight.HundredthSeconds) && + ( _rLeft.Seconds == _rRight.Seconds) && + ( _rLeft.Minutes == _rRight.Minutes) && + ( _rLeft.Hours == _rRight.Hours) ; +} + +//......................................................................... +} // namespace utl +//......................................................................... + diff --git a/unotools/source/misc/desktopterminationobserver.cxx b/unotools/source/misc/desktopterminationobserver.cxx new file mode 100644 index 000000000000..d30ea7cc281d --- /dev/null +++ b/unotools/source/misc/desktopterminationobserver.cxx @@ -0,0 +1,240 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: desktopterminationobserver.cxx,v $ + * $Revision: 1.6 $ + * + * 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_unotools.hxx" +#include <unotools/desktopterminationobserver.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +/** === end UNO includes === **/ +#include <cppuhelper/implbase1.hxx> +#include <comphelper/processfactory.hxx> + +#include <list> + +//........................................................................ +namespace utl +{ +//........................................................................ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::frame; + + namespace + { + //................................................................ + typedef ::std::list< ITerminationListener* > Listeners; + + struct ListenerAdminData + { + Listeners aListeners; + bool bAlreadyTerminated; + bool bCreatedAdapter; + + ListenerAdminData() : bAlreadyTerminated( false ), bCreatedAdapter( false ) { } + }; + + //................................................................ + ListenerAdminData& getListenerAdminData() + { + static ListenerAdminData s_aData; + return s_aData; + } + + //================================================================ + //= OObserverImpl + //================================================================ + class OObserverImpl : public ::cppu::WeakImplHelper1< XTerminateListener > + { + public: + static void ensureObservation(); + + protected: + OObserverImpl(); + ~OObserverImpl(); + + private: + // XTerminateListener + virtual void SAL_CALL queryTermination( const EventObject& Event ) throw (TerminationVetoException, RuntimeException); + virtual void SAL_CALL notifyTermination( const EventObject& Event ) throw (RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + }; + + //-------------------------------------------------------------------- + OObserverImpl::OObserverImpl() + { + } + + //-------------------------------------------------------------------- + OObserverImpl::~OObserverImpl() + { + } + + //-------------------------------------------------------------------- + void OObserverImpl::ensureObservation() + { + { + if ( getListenerAdminData().bCreatedAdapter ) + return; + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( getListenerAdminData().bCreatedAdapter ) + return; + + getListenerAdminData().bCreatedAdapter = true; + } + + try + { + Reference< XDesktop > xDesktop; + xDesktop = xDesktop.query( ::comphelper::getProcessServiceFactory()->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ) ) ); + OSL_ENSURE( xDesktop.is(), "OObserverImpl::ensureObservation: could not ensureObservation the desktop!" ); + if ( xDesktop.is() ) + xDesktop->addTerminateListener( new OObserverImpl ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "OObserverImpl::ensureObservation: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OObserverImpl::queryTermination( const EventObject& /*Event*/ ) throw (TerminationVetoException, RuntimeException) + { + Listeners aToNotify; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + aToNotify = getListenerAdminData().aListeners; + } + + for ( Listeners::const_iterator listener = aToNotify.begin(); + listener != aToNotify.end(); + ++listener + ) + { + if ( !(*listener)->queryTermination() ) + throw TerminationVetoException(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OObserverImpl::notifyTermination( const EventObject& /*Event*/ ) throw (RuntimeException) + { + // get the listeners + Listeners aToNotify; + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + OSL_ENSURE( !getListenerAdminData().bAlreadyTerminated, "OObserverImpl::notifyTermination: terminated twice?" ); + aToNotify = getListenerAdminData().aListeners; + getListenerAdminData().bAlreadyTerminated = true; + } + + // notify the listeners + for ( Listeners::const_iterator listener = aToNotify.begin(); + listener != aToNotify.end(); + ++listener + ) + { + (*listener)->notifyTermination(); + } + + // clear the listener container + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + getListenerAdminData().aListeners.clear(); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL OObserverImpl::disposing( const EventObject& /*Event*/ ) throw (RuntimeException) + { +#if OSL_DEBUG_LEVEL > 0 + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + OSL_ENSURE( getListenerAdminData().bAlreadyTerminated, "OObserverImpl::disposing: disposing without terminated?" ); +#endif + // not interested in + } + } + + //==================================================================== + //= DesktopTerminationObserver + //==================================================================== + //-------------------------------------------------------------------- + void DesktopTerminationObserver::registerTerminationListener( ITerminationListener* _pListener ) + { + if ( !_pListener ) + return; + + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( getListenerAdminData().bAlreadyTerminated ) + { + _pListener->notifyTermination(); + return; + } + + getListenerAdminData().aListeners.push_back( _pListener ); + } + + OObserverImpl::ensureObservation(); + } + + //-------------------------------------------------------------------- + void DesktopTerminationObserver::revokeTerminationListener( ITerminationListener* _pListener ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( getListenerAdminData().bAlreadyTerminated ) + { + _pListener->notifyTermination(); + return; + } + + Listeners& rListeners = getListenerAdminData().aListeners; + for ( Listeners::iterator lookup = rListeners.begin(); + lookup != rListeners.end(); + ++lookup + ) + { + if ( *lookup == _pListener ) + { + rListeners.erase( lookup ); + break; + } + } + } + +//........................................................................ +} // namespace utl +//........................................................................ + diff --git a/unotools/source/misc/eventlisteneradapter.cxx b/unotools/source/misc/eventlisteneradapter.cxx new file mode 100644 index 000000000000..b4c344e2cfd3 --- /dev/null +++ b/unotools/source/misc/eventlisteneradapter.cxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eventlisteneradapter.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" +#include <unotools/eventlisteneradapter.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/implbase1.hxx> +#include <comphelper/stl_types.hxx> + +//......................................................................... +namespace utl +{ +//......................................................................... + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + //===================================================================== + //= OEventListenerImpl + //===================================================================== + class OEventListenerImpl : public ::cppu::WeakImplHelper1< XEventListener > + { + protected: + OEventListenerAdapter* m_pAdapter; + Reference< XEventListener > m_xKeepMeAlive; + // imagine an implementation of XComponent which holds it's listeners with a weak reference ... + // would be very bad if we don't hold ourself + Reference< XComponent > m_xComponent; + + public: + OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp ); + + void dispose(); + const Reference< XComponent >& getComponent() const { return m_xComponent; } + + protected: + virtual void SAL_CALL disposing( const EventObject& _rSource ) throw (RuntimeException); + }; + + //--------------------------------------------------------------------- + OEventListenerImpl::OEventListenerImpl( OEventListenerAdapter* _pAdapter, const Reference< XComponent >& _rxComp ) + :m_pAdapter(_pAdapter) + { + OSL_ENSURE(m_pAdapter, "OEventListenerImpl::OEventListenerImpl: invalid adapter!"); + // no checks of _rxComp !! + // (OEventListenerAdapter is responsible for this) + + // just in case addEventListener throws an exception ... don't initialize m_xKeepMeAlive before this + // is done + Reference< XEventListener > xMeMyselfAndI = this; + _rxComp->addEventListener(xMeMyselfAndI); + + m_xComponent = _rxComp; + m_xKeepMeAlive = xMeMyselfAndI; + } + + //--------------------------------------------------------------------- + void OEventListenerImpl::dispose() + { + if (m_xComponent.is()) + { + m_xComponent->removeEventListener(m_xKeepMeAlive); + m_xComponent.clear(); + m_xKeepMeAlive.clear(); + } + } + + //--------------------------------------------------------------------- + void SAL_CALL OEventListenerImpl::disposing( const EventObject& _rSource ) throw (RuntimeException) + { + Reference< XEventListener > xDeleteUponLeaving = m_xKeepMeAlive; + m_xKeepMeAlive.clear(); + m_xComponent.clear(); + + m_pAdapter->_disposing(_rSource); + } + + //===================================================================== + //= OEventListenerAdapterImpl + //===================================================================== + struct OEventListenerAdapterImpl + { + public: + ::std::vector< void* > aListeners; + }; + + //===================================================================== + //= OEventListenerAdapter + //===================================================================== + //--------------------------------------------------------------------- + OEventListenerAdapter::OEventListenerAdapter() + :m_pImpl(new OEventListenerAdapterImpl) + { + } + + //--------------------------------------------------------------------- + OEventListenerAdapter::~OEventListenerAdapter() + { + stopAllComponentListening( ); + delete m_pImpl; + m_pImpl = NULL; + } + + //--------------------------------------------------------------------- + void OEventListenerAdapter::stopComponentListening( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& _rxComp ) + { + if ( m_pImpl->aListeners.empty() ) + return; + + ::std::vector< void* >::iterator dispose = m_pImpl->aListeners.begin(); + do + { + OEventListenerImpl* pListenerImpl = static_cast< OEventListenerImpl* >( *dispose ); + if ( pListenerImpl->getComponent().get() == _rxComp.get() ) + { + pListenerImpl->dispose(); + pListenerImpl->release(); + dispose = m_pImpl->aListeners.erase( dispose ); + } + else + ++dispose; + } + while ( dispose != m_pImpl->aListeners.end() ); + } + + //--------------------------------------------------------------------- + void OEventListenerAdapter::stopAllComponentListening( ) + { + for ( ::std::vector< void* >::const_iterator aDisposeLoop = m_pImpl->aListeners.begin(); + aDisposeLoop != m_pImpl->aListeners.end(); + ++aDisposeLoop + ) + { + OEventListenerImpl* pListenerImpl = static_cast< OEventListenerImpl* >(*aDisposeLoop); + pListenerImpl->dispose(); + pListenerImpl->release(); + } + m_pImpl->aListeners.clear(); + } + + //--------------------------------------------------------------------- + void OEventListenerAdapter::startComponentListening( const Reference< XComponent >& _rxComp ) + { + if (!_rxComp.is()) + { + OSL_ENSURE(sal_False, "OEventListenerAdapter::startComponentListening: invalid component!"); + return; + } + + OEventListenerImpl* pListenerImpl = new OEventListenerImpl(this, _rxComp); + pListenerImpl->acquire(); + m_pImpl->aListeners.push_back(pListenerImpl); + } + +//......................................................................... +} // namespace utl +//......................................................................... diff --git a/unotools/source/misc/makefile.mk b/unotools/source/misc/makefile.mk new file mode 100644 index 000000000000..8e505e41aaac --- /dev/null +++ b/unotools/source/misc/makefile.mk @@ -0,0 +1,56 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.18 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=misc + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/atom.obj \ + $(SLO)$/datetime.obj \ + $(SLO)$/eventlisteneradapter.obj \ + $(SLO)$/desktopterminationobserver.obj \ + $(SLO)$/sharedunocomponent.obj \ + $(SLO)$/componentresmodule.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/misc/sharedunocomponent.cxx b/unotools/source/misc/sharedunocomponent.cxx new file mode 100644 index 000000000000..a426a6662fa5 --- /dev/null +++ b/unotools/source/misc/sharedunocomponent.cxx @@ -0,0 +1,249 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sharedunocomponent.cxx,v $ + * $Revision: 1.7 $ + * + * 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_unotools.hxx" +#include <unotools/sharedunocomponent.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/util/XCloseable.hpp> +#include <cppuhelper/implbase1.hxx> +#include <tools/debug.hxx> + +//............................................................................ +namespace utl +{ +//............................................................................ + + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::util::XCloseable; + using ::com::sun::star::util::XCloseListener; + using ::com::sun::star::util::CloseVetoException; + + //======================================================================== + //= DisposableComponent + //======================================================================== + //------------------------------------------------------------------------ + DisposableComponent::DisposableComponent( const Reference< XInterface >& _rxComponent ) + :m_xComponent( _rxComponent, UNO_QUERY ) + { + DBG_ASSERT( m_xComponent.is() || !_rxComponent.is(), "DisposableComponent::DisposableComponent: should be an XComponent!" ); + } + + //------------------------------------------------------------------------ + DisposableComponent::~DisposableComponent() + { + if ( m_xComponent.is() ) + { + try + { + m_xComponent->dispose(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "DisposableComponent::~DisposableComponent: caught an exception!" ); + } + m_xComponent.clear(); + } + } + + //======================================================================== + //= CloseableComponentImpl + //======================================================================== + DBG_NAME( CloseableComponentImpl ) + typedef ::cppu::WeakImplHelper1 < XCloseListener + > CloseableComponentImpl_Base; + class CloseableComponentImpl : public CloseableComponentImpl_Base + { + private: + Reference< XCloseable > m_xCloseable; + + public: + CloseableComponentImpl( const Reference< XInterface >& _rxComponent ); + + /** closes the component + + @nofail + */ + void nf_closeComponent(); + + protected: + virtual ~CloseableComponentImpl(); + + // XCloseListener overridables + virtual void SAL_CALL queryClosing( const EventObject& Source, ::sal_Bool GetsOwnership ) throw (CloseVetoException, RuntimeException); + virtual void SAL_CALL notifyClosing( const EventObject& Source ) throw (RuntimeException); + + // XEventListener overridables + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + private: + /** starts or stops being a CloseListener at the component + + Only to be called upon construction of the instance, or when the component + is to be closed. + + @nofail + */ + void impl_nf_switchListening( bool _bListen ); + + + private: + CloseableComponentImpl(); // never implemented + CloseableComponentImpl( const CloseableComponentImpl& ); // never implemented + CloseableComponentImpl& operator=( const CloseableComponentImpl& ); // never implemented + }; + + //------------------------------------------------------------------------ + CloseableComponentImpl::CloseableComponentImpl( const Reference< XInterface >& _rxComponent ) + :m_xCloseable( _rxComponent, UNO_QUERY ) + { + DBG_CTOR( CloseableComponentImpl, NULL ); + DBG_ASSERT( m_xCloseable.is() || !_rxComponent.is(), "CloseableComponentImpl::CloseableComponentImpl: component is not an XCloseable!" ); + impl_nf_switchListening( true ); + } + //------------------------------------------------------------------------ + CloseableComponentImpl::~CloseableComponentImpl() + { + nf_closeComponent(); + DBG_DTOR( CloseableComponentImpl, NULL ); + } + + //------------------------------------------------------------------------ + void CloseableComponentImpl::nf_closeComponent() + { + if ( !m_xCloseable.is() ) + // nothing to do + return; + + // stop listening + impl_nf_switchListening( false ); + + // close + try + { + m_xCloseable->close( sal_True ); + } + catch( const CloseVetoException& ) { /* fine */ } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "CloseableComponentImpl::nf_closeComponent: caught an unexpected exception!" ); + } + + // reset + m_xCloseable.clear(); + } + + //------------------------------------------------------------------------ + void CloseableComponentImpl::impl_nf_switchListening( bool _bListen ) + { + if ( !m_xCloseable.is() ) + return; + + try + { + if ( _bListen ) + m_xCloseable->addCloseListener( this ); + else + m_xCloseable->removeCloseListener( this ); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "CloseableComponentImpl::impl_nf_switchListening: caught an exception!" ); + } + } + + //-------------------------------------------------------------------- + void SAL_CALL CloseableComponentImpl::queryClosing( const EventObject& + #ifdef DBG_UTIL + Source + #endif + , ::sal_Bool /*GetsOwnership*/ ) throw (CloseVetoException, RuntimeException) + { + // as long as we live, somebody wants to keep the object alive. So, veto the + // closing + DBG_ASSERT( Source.Source == m_xCloseable, "CloseableComponentImpl::queryClosing: where did this come from?" ); + throw CloseVetoException(); + } + + //-------------------------------------------------------------------- + void SAL_CALL CloseableComponentImpl::notifyClosing( const EventObject& + #ifdef DBG_UTIL + Source + #endif + ) throw (RuntimeException) + { + DBG_ASSERT( Source.Source == m_xCloseable, "CloseableComponentImpl::notifyClosing: where did this come from?" ); + + // this should be unreachable: As long as we're a CloseListener, we veto the closing. If we're going + // to close the component ourself, then we revoke ourself as listener *before* the close call. So, + // if this here fires, something went definately wrong. + DBG_ERROR( "CloseableComponentImpl::notifyClosing: unreachable!" ); + } + + //-------------------------------------------------------------------- + void SAL_CALL CloseableComponentImpl::disposing( const EventObject& + #ifdef DBG_UTIL + Source + #endif + ) throw (RuntimeException) + { + DBG_ASSERT( Source.Source == m_xCloseable, "CloseableComponentImpl::disposing: where did this come from?" ); + DBG_ERROR( "CloseableComponentImpl::disposing: unreachable!" ); + // same reasoning for this assertion as in ->notifyClosing + } + + //======================================================================== + //= CloseableComponentImpl + //======================================================================== + DBG_NAME( CloseableComponent ) + //------------------------------------------------------------------------ + CloseableComponent::CloseableComponent( const Reference< XInterface >& _rxComponent ) + :m_pImpl( new CloseableComponentImpl( _rxComponent ) ) + { + DBG_CTOR( CloseableComponent, NULL ); + } + + //------------------------------------------------------------------------ + CloseableComponent::~CloseableComponent() + { + // close the component, deliver ownership to anybody who wants to veto the close + m_pImpl->nf_closeComponent(); + DBG_DTOR( CloseableComponent, NULL ); + } + +//............................................................................ +} // namespace utl +//............................................................................ diff --git a/unotools/source/processfactory/componentfactory.cxx b/unotools/source/processfactory/componentfactory.cxx new file mode 100644 index 000000000000..690cd86b8124 --- /dev/null +++ b/unotools/source/processfactory/componentfactory.cxx @@ -0,0 +1,189 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: componentfactory.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" + +#include <unotools/componentfactory.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HDL_ +#include <com/sun/star/registry/XRegistryKey.hpp> +#endif + +#include <cppuhelper/factory.hxx> + +#include <uno/environment.h> +#include <uno/mapping.hxx> + +#include <rtl/ustring.hxx> +#include <osl/module.h> + + + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace ::rtl; + + +namespace utl +{ + +Reference< XInterface > getComponentInstance( + const OUString & rLibraryName, + const OUString & rImplementationName + ) +{ + Reference< XInterface > xI; + Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + if ( xMSF.is() ) + xI = xMSF->createInstance( rImplementationName ); + if( !xI.is() ) + { + Reference< XSingleServiceFactory > xSSF = + loadLibComponentFactory( rLibraryName, rImplementationName, + Reference< XMultiServiceFactory >(), Reference< XRegistryKey >() ); + xI = xSSF->createInstance(); + } + return xI; +} + + +Reference< XSingleServiceFactory > loadLibComponentFactory( + const OUString & rLibName, + const OUString & rImplName, + const Reference< XMultiServiceFactory > & xSF, + const Reference< XRegistryKey > & xKey + ) +{ + Reference< XSingleServiceFactory > xRet; + + oslModule lib = osl_loadModule( rLibName.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); + if (lib) + { + void * pSym; + + // ========================= LATEST VERSION ========================= + OUString aGetEnvName( RTL_CONSTASCII_USTRINGPARAM(COMPONENT_GETENV) ); + if (pSym = osl_getSymbol( lib, aGetEnvName.pData )) + { + uno_Environment * pCurrentEnv = 0; + uno_Environment * pEnv = 0; + const sal_Char * pEnvTypeName = 0; + (*((component_getImplementationEnvironmentFunc)pSym))( &pEnvTypeName, &pEnv ); + + sal_Bool bNeedsMapping = + (pEnv || 0 != rtl_str_compare( pEnvTypeName, CPPU_CURRENT_LANGUAGE_BINDING_NAME )); + + OUString aEnvTypeName( OUString::createFromAscii( pEnvTypeName ) ); + + if (bNeedsMapping) + { + if (! pEnv) + uno_getEnvironment( &pEnv, aEnvTypeName.pData, 0 ); + if (pEnv) + { + OUString aCppEnvTypeName( RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME) ); + uno_getEnvironment( &pCurrentEnv, aCppEnvTypeName.pData, 0 ); + if (pCurrentEnv) + bNeedsMapping = (pEnv != pCurrentEnv); + } + } + + OUString aGetFactoryName( RTL_CONSTASCII_USTRINGPARAM(COMPONENT_GETFACTORY) ); + if (pSym = osl_getSymbol( lib, aGetFactoryName.pData )) + { + OString aImplName( OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) ); + + if (bNeedsMapping) + { + if (pEnv && pCurrentEnv) + { + Mapping aCurrent2Env( pCurrentEnv, pEnv ); + Mapping aEnv2Current( pEnv, pCurrentEnv ); + + if (aCurrent2Env.is() && aEnv2Current.is()) + { + void * pSMgr = aCurrent2Env.mapInterface( + xSF.get(), ::getCppuType( (const Reference< XMultiServiceFactory > *)0 ) ); + void * pKey = aCurrent2Env.mapInterface( + xKey.get(), ::getCppuType( (const Reference< XRegistryKey > *)0 ) ); + + void * pSSF = (*((component_getFactoryFunc)pSym))( + aImplName.getStr(), pSMgr, pKey ); + + if (pKey) + (*pEnv->pExtEnv->releaseInterface)( pEnv->pExtEnv, pKey ); + if (pSMgr) + (*pEnv->pExtEnv->releaseInterface)( pEnv->pExtEnv, pSMgr ); + + if (pSSF) + { + aEnv2Current.mapInterface( + reinterpret_cast< void ** >( &xRet ), + pSSF, ::getCppuType( (const Reference< XSingleServiceFactory > *)0 ) ); + (*pEnv->pExtEnv->releaseInterface)( pEnv->pExtEnv, pSSF ); + } + } + } + } + else + { + XSingleServiceFactory * pRet = (XSingleServiceFactory *) + (*((component_getFactoryFunc)pSym))( + aImplName.getStr(), xSF.get(), xKey.get() ); + if (pRet) + { + xRet = pRet; + pRet->release(); + } + } + } + + if (pEnv) + (*pEnv->release)( pEnv ); + if (pCurrentEnv) + (*pCurrentEnv->release)( pCurrentEnv ); + } + + + if (! xRet.is()) + osl_unloadModule( lib ); + } + + return xRet; +} + +} // namespace utl diff --git a/unotools/source/processfactory/makefile.mk b/unotools/source/processfactory/makefile.mk new file mode 100644 index 000000000000..de27f67c982f --- /dev/null +++ b/unotools/source/processfactory/makefile.mk @@ -0,0 +1,54 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.6 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=procfact + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings common for the whole project ----- + + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/processfactory.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/processfactory/processfactory.cxx b/unotools/source/processfactory/processfactory.cxx new file mode 100644 index 000000000000..c8124bf106c8 --- /dev/null +++ b/unotools/source/processfactory/processfactory.cxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: processfactory.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" +#include <osl/mutex.hxx> +#include <unotools/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace osl; + +namespace utl +{ + // just use the comphelper versions of both functions. The versions here in unotools will become obsolete + // from SRC610 on. + + void setProcessServiceFactory(const Reference< XMultiServiceFactory >& xSMgr) + { + ::comphelper::setProcessServiceFactory(xSMgr); + } + + Reference< XMultiServiceFactory > getProcessServiceFactory() + { + return ::comphelper::getProcessServiceFactory(); + } + +} // namesapce utl + diff --git a/unotools/source/property/makefile.mk b/unotools/source/property/makefile.mk new file mode 100644 index 000000000000..292ef8cad062 --- /dev/null +++ b/unotools/source/property/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.10 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=property + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/propertysetinfo.obj \ + $(SLO)$/propertysethelper.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/property/propertysethelper.cxx b/unotools/source/property/propertysethelper.cxx new file mode 100644 index 000000000000..28dc143873d6 --- /dev/null +++ b/unotools/source/property/propertysethelper.cxx @@ -0,0 +1,304 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: propertysethelper.cxx,v $ + * $Revision: 1.6 $ + * + * 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_unotools.hxx" +#include <tools/debug.hxx> + +#include "unotools/propertysetinfo.hxx" +#include "unotools/propertysethelper.hxx" + +/////////////////////////////////////////////////////////////////////// + +using namespace ::utl; +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace utl +{ +class PropertySetHelperImpl +{ +public: + PropertyMapEntry* find( const OUString& aName ) const throw(); + + PropertySetInfo* mpInfo; +}; +} + +PropertyMapEntry* PropertySetHelperImpl::find( const OUString& aName ) const throw() +{ + PropertyMap::const_iterator aIter = mpInfo->getPropertyMap()->find( aName ); + + if( mpInfo->getPropertyMap()->end() != aIter ) + { + return (*aIter).second; + } + else + { + return NULL; + } +} + +/////////////////////////////////////////////////////////////////////// + +PropertySetHelper::PropertySetHelper( utl::PropertySetInfo* pInfo ) throw() +{ + mp = new PropertySetHelperImpl; + mp->mpInfo = pInfo; + pInfo->acquire(); +} + +PropertySetHelper::~PropertySetHelper() throw() +{ + mp->mpInfo->release(); + delete mp; +} + +// XPropertySet +Reference< XPropertySetInfo > SAL_CALL PropertySetHelper::getPropertySetInfo( ) throw(RuntimeException) +{ + return mp->mpInfo; +} + +void SAL_CALL PropertySetHelper::setPropertyValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + PropertyMapEntry* aEntries[2]; + aEntries[0] = mp->find( aPropertyName ); + + if( NULL == aEntries[0] ) + throw UnknownPropertyException(); + + aEntries[1] = NULL; + + _setPropertyValues( (const PropertyMapEntry**)aEntries, &aValue ); +} + +Any SAL_CALL PropertySetHelper::getPropertyValue( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertyMapEntry* aEntries[2]; + aEntries[0] = mp->find( PropertyName ); + + if( NULL == aEntries[0] ) + throw UnknownPropertyException(); + + aEntries[1] = NULL; + + Any aAny; + _getPropertyValues( (const PropertyMapEntry**)aEntries, &aAny ); + + return aAny; +} + +void SAL_CALL PropertySetHelper::addPropertyChangeListener( const ::rtl::OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::removePropertyChangeListener( const ::rtl::OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*aListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::addVetoableChangeListener( const ::rtl::OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::removeVetoableChangeListener( const ::rtl::OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + // todo +} + +// XMultiPropertySet +void SAL_CALL PropertySetHelper::setPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames, const Sequence< Any >& aValues ) throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + const sal_Int32 nCount = aPropertyNames.getLength(); + + if( nCount != aValues.getLength() ) + throw IllegalArgumentException(); + + if( nCount ) + { + PropertyMapEntry** pEntries = new PropertyMapEntry*[nCount+1]; + const OUString* pNames = aPropertyNames.getConstArray(); + + sal_Bool bUnknown = sal_False; + sal_Int32 n; + for( n = 0; !bUnknown && ( n < nCount ); n++, pNames++ ) + { + pEntries[n] = mp->find( *pNames ); + bUnknown = NULL == pEntries[n]; + } + + if( !bUnknown ) + _setPropertyValues( (const PropertyMapEntry**)pEntries, aValues.getConstArray() ); + + delete [] pEntries; + + if( bUnknown ) + throw UnknownPropertyException(); + } +} + +Sequence< Any > SAL_CALL PropertySetHelper::getPropertyValues( const Sequence< ::rtl::OUString >& aPropertyNames ) throw(RuntimeException) +{ + const sal_Int32 nCount = aPropertyNames.getLength(); + + Sequence< Any > aValues; + if( nCount ) + { + PropertyMapEntry** pEntries = new PropertyMapEntry*[nCount+1]; + const OUString* pNames = aPropertyNames.getConstArray(); + + sal_Bool bUnknown = sal_False; + sal_Int32 n; + for( n = 0; !bUnknown && ( n < nCount ); n++, pNames++ ) + { + pEntries[n] = mp->find( *pNames ); + bUnknown = NULL == pEntries[n]; + } + + if( !bUnknown ) + _getPropertyValues( (const PropertyMapEntry**)pEntries, aValues.getArray() ); + + delete [] pEntries; + + if( bUnknown ) + throw UnknownPropertyException(); + } + + return aValues; +} + +void SAL_CALL PropertySetHelper::addPropertiesChangeListener( const Sequence< ::rtl::OUString >& /*aPropertyNames*/, const Reference< XPropertiesChangeListener >& /*xListener*/ ) throw(RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& /*xListener*/ ) throw(RuntimeException) +{ + // todo +} + +void SAL_CALL PropertySetHelper::firePropertiesChangeEvent( const Sequence< ::rtl::OUString >& /*aPropertyNames*/, const Reference< XPropertiesChangeListener >& /*xListener*/ ) throw(RuntimeException) +{ + // todo +} + +// XPropertyState +PropertyState SAL_CALL PropertySetHelper::getPropertyState( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + PropertyMapEntry* aEntries[2]; + + aEntries[0] = mp->find( PropertyName ); + if( aEntries[0] == NULL ) + throw UnknownPropertyException(); + + aEntries[1] = NULL; + + PropertyState aState; + _getPropertyStates( (const PropertyMapEntry**)aEntries, &aState ); + + return aState; +} + +Sequence< PropertyState > SAL_CALL PropertySetHelper::getPropertyStates( const Sequence< ::rtl::OUString >& aPropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + const sal_Int32 nCount = aPropertyName.getLength(); + + Sequence< PropertyState > aStates( nCount ); + + if( nCount ) + { + const OUString* pNames = aPropertyName.getConstArray(); + + sal_Bool bUnknown = sal_False; + + PropertyMapEntry** pEntries = new PropertyMapEntry*[nCount+1]; + + sal_Int32 n; + for( n = 0; !bUnknown && (n < nCount); n++, pNames++ ) + { + pEntries[n] = mp->find( *pNames ); + bUnknown = NULL == pEntries[n]; + } + + pEntries[nCount] = NULL; + + if( !bUnknown ) + _getPropertyStates( (const PropertyMapEntry**)pEntries, aStates.getArray() ); + + delete [] pEntries; + + if( bUnknown ) + throw UnknownPropertyException(); + } + + return aStates; +} + +void SAL_CALL PropertySetHelper::setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + PropertyMapEntry *pEntry = mp->find( PropertyName ); + if( NULL == pEntry ) + throw UnknownPropertyException(); + + _setPropertyToDefault( pEntry ); +} + +Any SAL_CALL PropertySetHelper::getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + PropertyMapEntry* pEntry = mp->find( aPropertyName ); + if( NULL == pEntry ) + throw UnknownPropertyException(); + + return _getPropertyDefault( pEntry ); +} + +void PropertySetHelper::_getPropertyStates( const utl::PropertyMapEntry** /*ppEntries*/, PropertyState* /*pStates*/ ) throw(UnknownPropertyException ) +{ + DBG_ERROR( "you have to implement this yourself!" ); +} + +void PropertySetHelper::_setPropertyToDefault( const utl::PropertyMapEntry* /*pEntry*/ ) throw(UnknownPropertyException ) +{ + DBG_ERROR( "you have to implement this yourself!" ); +} + +Any PropertySetHelper::_getPropertyDefault( const utl::PropertyMapEntry* /*pEntry*/ ) throw(UnknownPropertyException, WrappedTargetException ) +{ + DBG_ERROR( "you have to implement this yourself!" ); + + Any aAny; + return aAny; +} diff --git a/unotools/source/property/propertysetinfo.cxx b/unotools/source/property/propertysetinfo.cxx new file mode 100644 index 000000000000..b8b5f8bb5125 --- /dev/null +++ b/unotools/source/property/propertysetinfo.cxx @@ -0,0 +1,202 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: propertysetinfo.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" +#include <tools/debug.hxx> + +#include "unotools/propertysetinfo.hxx" + +using namespace ::utl; +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace utl +{ +class PropertyMapImpl +{ +public: + PropertyMapImpl() throw(); + virtual ~PropertyMapImpl() throw(); + + void add( PropertyMapEntry* pMap ) throw(); + void remove( const OUString& aName ) throw(); + + Sequence< Property > getProperties() throw(); + + const PropertyMap* getPropertyMap() const throw(); + + Property getPropertyByName( const OUString& aName ) throw( UnknownPropertyException ); + sal_Bool hasPropertyByName( const OUString& aName ) throw(); + +private: + PropertyMap maPropertyMap; + Sequence< Property > maProperties; +}; +} + +PropertyMapImpl::PropertyMapImpl() throw() +{ +} + +PropertyMapImpl::~PropertyMapImpl() throw() +{ +} + +void PropertyMapImpl::add( PropertyMapEntry* pMap ) throw() +{ + while( pMap->mpName ) + { + OUString aName( pMap->mpName, pMap->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + +#ifndef PRODUCT + PropertyMap::iterator aIter = maPropertyMap.find( aName ); + if( aIter != maPropertyMap.end() ) + { + DBG_ERROR( "Warning: PropertyMapEntry added twice, possible error!" ); + } +#endif + if( NULL == pMap->mpType ) + { + DBG_ERROR( "No type in PropertyMapEntry!" ); + pMap->mpType = &::getCppuType((const sal_Int32*)0); + } + + maPropertyMap[aName] = pMap; + + if( maProperties.getLength() ) + maProperties.realloc( 0 ); + + pMap = &pMap[1]; + } +} + +void PropertyMapImpl::remove( const OUString& aName ) throw() +{ + maPropertyMap.erase( aName ); + + if( maProperties.getLength() ) + maProperties.realloc( 0 ); +} + +Sequence< Property > PropertyMapImpl::getProperties() throw() +{ + // maybe we have to generate the properties after + // a change in the property map or at first call + // to getProperties + if( maProperties.getLength() != (sal_Int32)maPropertyMap.size() ) + { + maProperties = Sequence< Property >( maPropertyMap.size() ); + Property* pProperties = maProperties.getArray(); + + PropertyMap::iterator aIter = maPropertyMap.begin(); + const PropertyMap::iterator aEnd = maPropertyMap.end(); + while( aIter != aEnd ) + { + PropertyMapEntry* pEntry = (*aIter).second; + + pProperties->Name = OUString( pEntry->mpName, pEntry->mnNameLen, RTL_TEXTENCODING_ASCII_US ); + pProperties->Handle = pEntry->mnWhich; + pProperties->Type = *pEntry->mpType; + pProperties->Attributes = pEntry->mnFlags; + pProperties++; + aIter++; + } + } + + return maProperties; +} + +const PropertyMap* PropertyMapImpl::getPropertyMap() const throw() +{ + return &maPropertyMap; +} + +Property PropertyMapImpl::getPropertyByName( const OUString& aName ) throw( UnknownPropertyException ) +{ + PropertyMap::iterator aIter = maPropertyMap.find( aName ); + + if( maPropertyMap.end() == aIter ) + throw UnknownPropertyException(); + + PropertyMapEntry* pEntry = (*aIter).second; + + return Property( aName, pEntry->mnWhich, *pEntry->mpType, pEntry->mnFlags ); +} + +sal_Bool PropertyMapImpl::hasPropertyByName( const OUString& aName ) throw() +{ + return maPropertyMap.find( aName ) != maPropertyMap.end(); +} + +/////////////////////////////////////////////////////////////////////// + +PropertySetInfo::PropertySetInfo() throw() +{ + mpMap = new PropertyMapImpl(); +} + +PropertySetInfo::~PropertySetInfo() throw() +{ + delete mpMap; +} + +void PropertySetInfo::add( PropertyMapEntry* pMap ) throw() +{ + mpMap->add( pMap ); +} + +void PropertySetInfo::remove( const rtl::OUString& aName ) throw() +{ + mpMap->remove( aName ); +} + +Sequence< ::com::sun::star::beans::Property > SAL_CALL PropertySetInfo::getProperties() throw(::com::sun::star::uno::RuntimeException) +{ + return mpMap->getProperties(); +} + +Property SAL_CALL PropertySetInfo::getPropertyByName( const ::rtl::OUString& aName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException) +{ + return mpMap->getPropertyByName( aName ); +} + +sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName( const ::rtl::OUString& Name ) throw(::com::sun::star::uno::RuntimeException) +{ + return mpMap->hasPropertyByName( Name ); +} + +const PropertyMap* PropertySetInfo::getPropertyMap() const throw() +{ + return mpMap->getPropertyMap(); +} diff --git a/unotools/source/streaming/makefile.mk b/unotools/source/streaming/makefile.mk new file mode 100644 index 000000000000..db53632a7170 --- /dev/null +++ b/unotools/source/streaming/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.8 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=streaming + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES= $(SLO)$/streamhelper.obj \ + $(SLO)$/streamwrap.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/streaming/streamhelper.cxx b/unotools/source/streaming/streamhelper.cxx new file mode 100644 index 000000000000..f21872c67a5b --- /dev/null +++ b/unotools/source/streaming/streamhelper.cxx @@ -0,0 +1,207 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: streamhelper.cxx,v $ + * $Revision: 1.8 $ + * + * 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_unotools.hxx" +#include <unotools/streamhelper.hxx> +#include <tools/debug.hxx> + +namespace utl +{ + +//------------------------------------------------------------------------------ +void SAL_CALL OInputStreamHelper::acquire() throw () +{ + InputStreamHelper_Base::acquire(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OInputStreamHelper::release() throw () +{ + InputStreamHelper_Base::release(); +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OInputStreamHelper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) + throw(stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException) +{ + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + if (nBytesToRead < 0) + throw stario::BufferSizeExceededException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + ::osl::MutexGuard aGuard( m_aMutex ); + aData.realloc(nBytesToRead); + + sal_Size nRead; + ErrCode nError = m_xLockBytes->ReadAt(m_nActPos, (void*)aData.getArray(), nBytesToRead, &nRead); + // FIXME nRead could be truncated on 64-bit arches + m_nActPos += (sal_uInt32)nRead; + + if (nError != ERRCODE_NONE) + throw stario::IOException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + // adjust sequence if data read is lower than the desired data + if (nRead < (sal_uInt32)nBytesToRead) + aData.realloc( nRead ); + + return nRead; +} + +void SAL_CALL OInputStreamHelper::seek( sal_Int64 location ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // cast is truncating, but position would be truncated as soon as + // put into SvLockBytes anyway + m_nActPos = sal::static_int_cast<sal_uInt32>(location); +} + +sal_Int64 SAL_CALL OInputStreamHelper::getPosition( ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + return m_nActPos; +} + +sal_Int64 SAL_CALL OInputStreamHelper::getLength( ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + if (!m_xLockBytes.Is()) + return 0; + + ::osl::MutexGuard aGuard( m_aMutex ); + SvLockBytesStat aStat; + m_xLockBytes->Stat( &aStat, SVSTATFLAG_DEFAULT ); + return aStat.nSize; +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OInputStreamHelper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData, + sal_Int32 nMaxBytesToRead) + throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException) +{ + // read all data desired + return readBytes(aData, nMaxBytesToRead); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OInputStreamHelper::skipBytes(sal_Int32 nBytesToSkip) + throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + if (nBytesToSkip < 0) + throw stario::BufferSizeExceededException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + m_nActPos += nBytesToSkip; +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OInputStreamHelper::available() + throw (stario::NotConnectedException, stario::IOException, staruno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + return m_nAvailable; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OInputStreamHelper::closeInput() + throw (stario::NotConnectedException, stario::IOException, staruno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + m_xLockBytes = NULL; +} + +/*************************************************************************/ +//------------------------------------------------------------------------------ +void SAL_CALL OOutputStreamHelper::acquire() throw () +{ + OutputStreamHelper_Base::acquire(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OOutputStreamHelper::release() throw () +{ + OutputStreamHelper_Base::release(); +} +// stario::XOutputStream +//------------------------------------------------------------------------------ +void SAL_CALL OOutputStreamHelper::writeBytes(const staruno::Sequence< sal_Int8 >& aData) + throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + sal_Size nWritten; + ErrCode nError = m_xLockBytes->WriteAt( m_nActPos, aData.getConstArray(), aData.getLength(), &nWritten ); + // FIXME nWritten could be truncated on 64-bit arches + m_nActPos += (sal_uInt32)nWritten; + + if (nError != ERRCODE_NONE || + sal::static_int_cast<sal_Int32>(nWritten) != aData.getLength()) + { + throw stario::IOException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + } +} + +//------------------------------------------------------------------ +void SAL_CALL OOutputStreamHelper::flush() + throw (stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + ErrCode nError = m_xLockBytes->Flush(); + if (nError != ERRCODE_NONE) + throw stario::IOException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); +} + +//------------------------------------------------------------------ +void SAL_CALL OOutputStreamHelper::closeOutput( ) + throw(stario::NotConnectedException, stario::BufferSizeExceededException, stario::IOException, staruno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xLockBytes.Is()) + throw stario::NotConnectedException(::rtl::OUString(), static_cast<staruno::XWeak*>(this)); + + m_xLockBytes = NULL; +} + +} // namespace utl + + diff --git a/unotools/source/streaming/streamwrap.cxx b/unotools/source/streaming/streamwrap.cxx new file mode 100644 index 000000000000..b9f03b022d6e --- /dev/null +++ b/unotools/source/streaming/streamwrap.cxx @@ -0,0 +1,382 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: streamwrap.cxx,v $ + * $Revision: 1.8 $ + * + * 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_unotools.hxx" +#include <unotools/streamwrap.hxx> +#include <tools/stream.hxx> +#include <tools/debug.hxx> + +namespace utl +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; + +//================================================================== +//= OInputStreamWrapper +//================================================================== +DBG_NAME(OInputStreamWrapper) +//------------------------------------------------------------------ +OInputStreamWrapper::OInputStreamWrapper( SvStream& _rStream ) + :m_pSvStream(&_rStream) + ,m_bSvStreamOwner(sal_False) +{ + DBG_CTOR(OInputStreamWrapper,NULL); + +} + +//------------------------------------------------------------------ +OInputStreamWrapper::OInputStreamWrapper( SvStream* pStream, sal_Bool bOwner ) + :m_pSvStream( pStream ) + ,m_bSvStreamOwner( bOwner ) +{ + DBG_CTOR(OInputStreamWrapper,NULL); + +} + +//------------------------------------------------------------------ +OInputStreamWrapper::~OInputStreamWrapper() +{ + if( m_bSvStreamOwner ) + delete m_pSvStream; + + DBG_DTOR(OInputStreamWrapper,NULL); +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OInputStreamWrapper::readBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) + throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + checkConnected(); + + if (nBytesToRead < 0) + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + ::osl::MutexGuard aGuard( m_aMutex ); + + aData.realloc(nBytesToRead); + + sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead); + checkError(); + + // Wenn gelesene Zeichen < MaxLength, staruno::Sequence anpassen + if (nRead < (sal_uInt32)nBytesToRead) + aData.realloc( nRead ); + + return nRead; +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OInputStreamWrapper::readSomeBytes(staruno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + checkError(); + + if (nMaxBytesToRead < 0) + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + + if (m_pSvStream->IsEof()) + { + aData.realloc(0); + return 0; + } + else + return readBytes(aData, nMaxBytesToRead); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OInputStreamWrapper::skipBytes(sal_Int32 nBytesToSkip) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkError(); + +#ifdef DBG_UTIL + sal_uInt32 nCurrentPos = m_pSvStream->Tell(); +#endif + + m_pSvStream->SeekRel(nBytesToSkip); + checkError(); + +#ifdef DBG_UTIL + nCurrentPos = m_pSvStream->Tell(); +#endif +} + +//------------------------------------------------------------------------------ +sal_Int32 SAL_CALL OInputStreamWrapper::available() throw( stario::NotConnectedException, staruno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkConnected(); + + sal_uInt32 nPos = m_pSvStream->Tell(); + checkError(); + + m_pSvStream->Seek(STREAM_SEEK_TO_END); + checkError(); + + sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos; + m_pSvStream->Seek(nPos); + checkError(); + + return nAvailable; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OInputStreamWrapper::closeInput() throw( stario::NotConnectedException, staruno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkConnected(); + + if (m_bSvStreamOwner) + delete m_pSvStream; + + m_pSvStream = NULL; +} + +//------------------------------------------------------------------------------ +void OInputStreamWrapper::checkConnected() const +{ + if (!m_pSvStream) + throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this))); +} + +//------------------------------------------------------------------------------ +void OInputStreamWrapper::checkError() const +{ + checkConnected(); + + if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE) + // TODO: really evaluate the error + throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this))); +} + +//================================================================== +//= OSeekableInputStreamWrapper +//================================================================== +//------------------------------------------------------------------------------ +OSeekableInputStreamWrapper::OSeekableInputStreamWrapper(SvStream& _rStream) +{ + SetStream( &_rStream, FALSE ); +} + +//------------------------------------------------------------------------------ +OSeekableInputStreamWrapper::OSeekableInputStreamWrapper(SvStream* _pStream, sal_Bool _bOwner) +{ + SetStream( _pStream, _bOwner ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OSeekableInputStreamWrapper::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkConnected(); + + m_pSvStream->Seek((sal_uInt32)_nLocation); + checkError(); +} + +//------------------------------------------------------------------------------ +sal_Int64 SAL_CALL OSeekableInputStreamWrapper::getPosition( ) throw (IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkConnected(); + + sal_uInt32 nPos = m_pSvStream->Tell(); + checkError(); + return (sal_Int64)nPos; +} + +//------------------------------------------------------------------------------ +sal_Int64 SAL_CALL OSeekableInputStreamWrapper::getLength( ) throw (IOException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkConnected(); + + sal_uInt32 nCurrentPos = m_pSvStream->Tell(); + checkError(); + + m_pSvStream->Seek(STREAM_SEEK_TO_END); + sal_uInt32 nEndPos = m_pSvStream->Tell(); + m_pSvStream->Seek(nCurrentPos); + + checkError(); + + return (sal_Int64)nEndPos; +} + +//================================================================== +//= OOutputStreamWrapper +//================================================================== +//------------------------------------------------------------------------------ +void SAL_CALL OOutputStreamWrapper::writeBytes(const staruno::Sequence< sal_Int8 >& aData) throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + sal_uInt32 nWritten = rStream.Write(aData.getConstArray(),aData.getLength()); + ErrCode err = rStream.GetError(); + if ( (ERRCODE_NONE != err) + || (nWritten != (sal_uInt32)aData.getLength()) + ) + { + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + } +} + +//------------------------------------------------------------------ +void SAL_CALL OOutputStreamWrapper::flush() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ + rStream.Flush(); + checkError(); +} + +//------------------------------------------------------------------ +void SAL_CALL OOutputStreamWrapper::closeOutput() throw( stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException ) +{ +} + +//------------------------------------------------------------------------------ +void OOutputStreamWrapper::checkError() const +{ + if (rStream.GetError() != ERRCODE_NONE) + // TODO: really evaluate the error + throw stario::NotConnectedException(::rtl::OUString(), const_cast<staruno::XWeak*>(static_cast<const staruno::XWeak*>(this))); +} + +//================================================================== +//= OSeekableOutputStreamWrapper +//================================================================== +//------------------------------------------------------------------------------ +OSeekableOutputStreamWrapper::OSeekableOutputStreamWrapper(SvStream& _rStream) + :OOutputStreamWrapper(_rStream) +{ +} + +//------------------------------------------------------------------------------ +Any SAL_CALL OSeekableOutputStreamWrapper::queryInterface( const Type& _rType ) throw (RuntimeException) +{ + Any aReturn = OOutputStreamWrapper::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = OSeekableOutputStreamWrapper_Base::queryInterface(_rType); + return aReturn; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OSeekableOutputStreamWrapper::acquire( ) throw () +{ + OOutputStreamWrapper::acquire(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OSeekableOutputStreamWrapper::release( ) throw () +{ + OOutputStreamWrapper::release(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OSeekableOutputStreamWrapper::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException) +{ + rStream.Seek((sal_uInt32)_nLocation); + checkError(); +} + +//------------------------------------------------------------------------------ +sal_Int64 SAL_CALL OSeekableOutputStreamWrapper::getPosition( ) throw (IOException, RuntimeException) +{ + sal_uInt32 nPos = rStream.Tell(); + checkError(); + return (sal_Int64)nPos; +} + +//------------------------------------------------------------------------------ +sal_Int64 SAL_CALL OSeekableOutputStreamWrapper::getLength( ) throw (IOException, RuntimeException) +{ + sal_uInt32 nCurrentPos = rStream.Tell(); + checkError(); + + rStream.Seek(STREAM_SEEK_TO_END); + sal_uInt32 nEndPos = rStream.Tell(); + rStream.Seek(nCurrentPos); + + checkError(); + + return (sal_Int64)nEndPos; +} + +//------------------------------------------------------------------------------ +OStreamWrapper::OStreamWrapper(SvStream& _rStream) +{ + SetStream( &_rStream, FALSE ); +} + +//------------------------------------------------------------------------------ +::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL OStreamWrapper::getInputStream( ) throw (::com::sun::star::uno::RuntimeException) +{ + return this; +} + +//------------------------------------------------------------------------------ +::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL OStreamWrapper::getOutputStream( ) throw (::com::sun::star::uno::RuntimeException) +{ + return this; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OStreamWrapper::writeBytes(const staruno::Sequence< sal_Int8 >& aData) throw(stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException) +{ + sal_uInt32 nWritten = m_pSvStream->Write(aData.getConstArray(),aData.getLength()); + ErrCode err = m_pSvStream->GetError(); + if ( (ERRCODE_NONE != err) + || (nWritten != (sal_uInt32)aData.getLength()) + ) + { + throw stario::BufferSizeExceededException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL OStreamWrapper::flush() throw(stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException) +{ + m_pSvStream->Flush(); + if (m_pSvStream->GetError() != ERRCODE_NONE) + throw stario::NotConnectedException(::rtl::OUString(),static_cast<staruno::XWeak*>(this)); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OStreamWrapper::closeOutput() throw(stario::NotConnectedException, stario::BufferSizeExceededException, staruno::RuntimeException) +{ +} + +//------------------------------------------------------------------------------ +void SAL_CALL OStreamWrapper::truncate() throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + m_pSvStream->SetStreamSize(0); +} + +} // namespace utl + diff --git a/unotools/source/ucbhelper/XTempFile.hxx b/unotools/source/ucbhelper/XTempFile.hxx new file mode 100644 index 000000000000..34aa18f04829 --- /dev/null +++ b/unotools/source/ucbhelper/XTempFile.hxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XTempFile.hxx,v $ + * $Revision: 1.11 $ + * + * 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. + * + ************************************************************************/ +#ifndef _XTEMPFILE_HXX_ +#define _XTEMPFILE_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XTempFile.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase5.hxx> +#ifndef _CPPUHELPER_PROPERTYSETMIXIN_HXX_ +#include <cppuhelper/propertysetmixin.hxx> +#endif +#include <osl/mutex.hxx> + +class SvStream; +namespace utl { class TempFile; } + +typedef ::cppu::WeakImplHelper5< ::com::sun::star::io::XTempFile + , ::com::sun::star::io::XInputStream + , ::com::sun::star::io::XOutputStream + , ::com::sun::star::io::XTruncate + , ::com::sun::star::lang::XServiceInfo + > + OTempFileBase; + +class OTempFileService : + public OTempFileBase, + public ::cppu::PropertySetMixin< ::com::sun::star::io::XTempFile > +{ +protected: + ::utl::TempFile* mpTempFile; + ::osl::Mutex maMutex; + SvStream* mpStream; + sal_Bool mbRemoveFile; + sal_Bool mbInClosed; + sal_Bool mbOutClosed; + + sal_Int64 mnCachedPos; + sal_Bool mbHasCachedPos; + + void checkError () const; + void checkConnected (); + +public: + OTempFileService (::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & context); + + //Methods + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL acquire( ) + throw (); + virtual void SAL_CALL release( ) + throw (); + // XTypeProvider + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL getImplementationId( ) + throw (::com::sun::star::uno::RuntimeException); + + // XTempFile + virtual ::sal_Bool SAL_CALL getRemoveFile() + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setRemoveFile( ::sal_Bool _removefile ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getUri() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getResourceName() + throw (::com::sun::star::uno::RuntimeException); + + // XInputStream + virtual ::sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL available( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XOutputStream + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL flush( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeOutput( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition( ) + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength( ) + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XStream + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream( ) + throw (::com::sun::star::uno::RuntimeException); + // XTruncate + virtual void SAL_CALL truncate() + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() + throw (::com::sun::star::uno::RuntimeException); + + //::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface > SAL_CALL XTempFile_createInstance( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & context); + static ::rtl::OUString getImplementationName_Static (); + static ::com::sun::star::uno::Sequence < ::rtl::OUString > getSupportedServiceNames_Static(); + + static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleComponentFactory > createServiceFactory_Static( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory ); + +private: + OTempFileService( OTempFileService & ); + virtual ~OTempFileService (); + +}; +#endif diff --git a/unotools/source/ucbhelper/localfilehelper.cxx b/unotools/source/ucbhelper/localfilehelper.cxx new file mode 100644 index 000000000000..81ee866eda2b --- /dev/null +++ b/unotools/source/ucbhelper/localfilehelper.cxx @@ -0,0 +1,245 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: localfilehelper.cxx,v $ + * $Revision: 1.19 $ + * + * 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_unotools.hxx" +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> + +#include <unotools/localfilehelper.hxx> +#include <ucbhelper/fileidentifierconverter.hxx> +#include <ucbhelper/contentbroker.hxx> +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include <tools/urlobj.hxx> +#include <ucbhelper/content.hxx> + +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; + +namespace utl +{ + +sal_Bool LocalFileHelper::ConvertSystemPathToURL( const String& rName, const String& rBaseURL, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + rtl::OUString aRet; + if ( FileBase::getFileURLFromSystemPath( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + rReturn = ::ucbhelper::getFileURLFromSystemPath( xManager, rBaseURL, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + return sal_False; + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::ConvertURLToSystemPath( const String& rName, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + rtl::OUString aRet; + if( FileBase::getSystemPathFromFileURL( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + rReturn = ::ucbhelper::getSystemPathFromFileURL( xManager, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::ConvertPhysicalNameToURL( const String& rName, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + rtl::OUString aRet; + if ( FileBase::getFileURLFromSystemPath( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + + try + { + rtl::OUString aBase( ::ucbhelper::getLocalFileURL( xManager ) ); + rReturn = ::ucbhelper::getFileURLFromSystemPath( xManager, aBase, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::ConvertURLToPhysicalName( const String& rName, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + ::rtl::OUString aRet; + if ( FileBase::getSystemPathFromFileURL( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + INetURLObject aObj( rName ); + INetURLObject aLocal( ::ucbhelper::getLocalFileURL( xManager ) ); + if ( aObj.GetProtocol() == aLocal.GetProtocol() ) + rReturn = ::ucbhelper::getSystemPathFromFileURL( xManager, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::IsLocalFile( const String& rName ) +{ + String aTmp; + return ConvertURLToPhysicalName( rName, aTmp ); +} + +sal_Bool LocalFileHelper::IsFileContent( const String& rName ) +{ + String aTmp; + return ConvertURLToSystemPath( rName, aTmp ); +} + +DECLARE_LIST( StringList_Impl, ::rtl::OUString* ) + +::com::sun::star::uno::Sequence < ::rtl::OUString > LocalFileHelper::GetFolderContents( const ::rtl::OUString& rFolder, sal_Bool bFolder ) +{ + StringList_Impl* pFiles = NULL; + try + { + ::ucbhelper::Content aCnt( rFolder, Reference< XCommandEnvironment > () ); + Reference< ::com::sun::star::sdbc::XResultSet > xResultSet; + ::com::sun::star::uno::Sequence< ::rtl::OUString > aProps(1); + ::rtl::OUString* pProps = aProps.getArray(); + pProps[0] = ::rtl::OUString::createFromAscii( "Url" ); + + try + { + ::ucbhelper::ResultSetInclude eInclude = bFolder ? ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS : ::ucbhelper::INCLUDE_DOCUMENTS_ONLY; + xResultSet = aCnt.createCursor( aProps, eInclude ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( Exception& ) + { + } + + if ( xResultSet.is() ) + { + pFiles = new StringList_Impl; + Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + try + { + while ( xResultSet->next() ) + { + ::rtl::OUString aId = xContentAccess->queryContentIdentifierString(); + ::rtl::OUString* pFile = new ::rtl::OUString( aId ); + pFiles->Insert( pFile, LIST_APPEND ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( Exception& ) + { + } + } + } + catch( Exception& ) + { + } + + if ( pFiles ) + { + ULONG nCount = pFiles->Count(); + Sequence < ::rtl::OUString > aRet( nCount ); + ::rtl::OUString* pRet = aRet.getArray(); + for ( USHORT i = 0; i < nCount; ++i ) + { + ::rtl::OUString* pFile = pFiles->GetObject(i); + pRet[i] = *( pFile ); + delete pFile; + } + delete pFiles; + return aRet; + } + else + return Sequence < ::rtl::OUString > (); +} + +} diff --git a/unotools/source/ucbhelper/makefile.mk b/unotools/source/ucbhelper/makefile.mk new file mode 100644 index 000000000000..850a6ea532a3 --- /dev/null +++ b/unotools/source/ucbhelper/makefile.mk @@ -0,0 +1,58 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.17 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=ucbhelp + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES=\ + $(SLO)$/ucblockbytes.obj \ + $(SLO)$/localfilehelper.obj \ + $(SLO)$/ucbhelper.obj \ + $(SLO)$/ucbstreamhelper.obj \ + $(SLO)$/tempfile.obj \ + $(SLO)$/xtempfile.obj \ + $(SLO)$/progresshandlerwrap.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/ucbhelper/progresshandlerwrap.cxx b/unotools/source/ucbhelper/progresshandlerwrap.cxx new file mode 100644 index 000000000000..540ded03e90b --- /dev/null +++ b/unotools/source/ucbhelper/progresshandlerwrap.cxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: progresshandlerwrap.cxx,v $ + * $Revision: 1.5 $ + * + * 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_unotools.hxx" +#include <unotools/progresshandlerwrap.hxx> + +namespace utl +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::ucb; + +ProgressHandlerWrap::ProgressHandlerWrap( ::com::sun::star::uno::Reference< ::com::sun::star::task::XStatusIndicator > xSI ) +: m_xStatusIndicator( xSI ) +{ +} + +sal_Bool getStatusFromAny_Impl( const Any& aAny, ::rtl::OUString& aText, sal_Int32& nNum ) +{ + sal_Bool bNumIsSet = sal_False; + + Sequence< Any > aSetList; + if( ( aAny >>= aSetList ) && aSetList.getLength() ) + for( int ind = 0; ind < aSetList.getLength(); ind++ ) + { + if( !bNumIsSet && ( aSetList[ind] >>= nNum ) ) + bNumIsSet = sal_True; + else + !aText.getLength() && ( aSetList[ind] >>= aText ); + } + + return bNumIsSet; +} + +void SAL_CALL ProgressHandlerWrap::push( const Any& Status ) + throw( RuntimeException ) +{ + if( !m_xStatusIndicator.is() ) + return; + + ::rtl::OUString aText; + sal_Int32 nRange; + + if( getStatusFromAny_Impl( Status, aText, nRange ) ) + m_xStatusIndicator->start( aText, nRange ); +} + +void SAL_CALL ProgressHandlerWrap::update( const Any& Status ) + throw( RuntimeException ) +{ + if( !m_xStatusIndicator.is() ) + return; + + ::rtl::OUString aText; + sal_Int32 nValue; + + if( getStatusFromAny_Impl( Status, aText, nValue ) ) + { + if( aText.getLength() ) m_xStatusIndicator->setText( aText ); + m_xStatusIndicator->setValue( nValue ); + } +} + +void SAL_CALL ProgressHandlerWrap::pop() + throw( RuntimeException ) +{ + if( m_xStatusIndicator.is() ) + m_xStatusIndicator->end(); +} + +} // namespace utl + diff --git a/unotools/source/ucbhelper/tempfile.cxx b/unotools/source/ucbhelper/tempfile.cxx new file mode 100644 index 000000000000..36d738042400 --- /dev/null +++ b/unotools/source/ucbhelper/tempfile.cxx @@ -0,0 +1,496 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: tempfile.cxx,v $ + * $Revision: 1.28 $ + * + * 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_unotools.hxx" + +#include <unotools/tempfile.hxx> +#include <tools/tempfile.hxx> +#include <unotools/localfilehelper.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <ucbhelper/fileidentifierconverter.hxx> +#include <ucbhelper/contentbroker.hxx> +#include <rtl/ustring.hxx> +#include <rtl/instance.hxx> +#include <osl/file.hxx> +#include <tools/time.hxx> +#include <tools/debug.hxx> +#include <stdio.h> + +#ifdef UNX +#include <sys/stat.h> +#endif + +using namespace osl; + +namespace +{ + struct TempNameBase_Impl + : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {}; +} + +namespace utl +{ + +struct TempFile_Impl +{ + String aName; + String aURL; + SvStream* pStream; + sal_Bool bIsDirectory; + + TempFile_Impl() + : pStream(0) + {} +}; + +rtl::OUString getParentName( const rtl::OUString& aFileName ) +{ + sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') ); + rtl::OUString aParent = aFileName.copy( 0,lastIndex ); + + if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 ) + aParent += rtl::OUString::createFromAscii( "/" ); + + if( 0 == aParent.compareToAscii( "file://" ) ) + aParent = rtl::OUString::createFromAscii( "file:///" ); + + return aParent; +} + +sal_Bool ensuredir( const rtl::OUString& rUnqPath ) +{ + rtl::OUString aPath; + if ( rUnqPath.getLength() < 1 ) + return sal_False; + + // remove trailing slash + if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) ) + aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 ); + else + aPath = rUnqPath; + + // HACK: create directory on a mount point with nobrowse option + // returns ENOSYS in any case !! + osl::Directory aDirectory( aPath ); +#ifdef UNX +/* RW permission for the user only! */ + mode_t old_mode = umask(077); +#endif + osl::FileBase::RC nError = aDirectory.open(); +#ifdef UNX +umask(old_mode); +#endif + aDirectory.close(); + if( nError == osl::File::E_None ) + return sal_True; + + // try to create the directory + nError = osl::Directory::create( aPath ); + sal_Bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST ); + if( !bSuccess ) + { + // perhaps parent(s) don't exist + rtl::OUString aParentDir = getParentName( aPath ); + if ( aParentDir != aPath ) + { + bSuccess = ensuredir( getParentName( aPath ) ); + + // After parent directory structure exists try it one's more + if ( bSuccess ) + { + // Parent directory exists, retry creation of directory + nError = osl::Directory::create( aPath ); + bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST ); + } + } + } + + return bSuccess; +} + +#define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 ) +String ConstructTempDir_Impl( const String* pParent ) +{ + String aName; + if ( pParent && pParent->Len() ) + { + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( pBroker ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + + // if parent given try to use it + rtl::OUString aTmp( *pParent ); + + // test for valid filename + rtl::OUString aRet; + ::osl::FileBase::getFileURLFromSystemPath( + ::ucbhelper::getSystemPathFromFileURL( xManager, aTmp ), + aRet ); + if ( aRet.getLength() ) + { + ::osl::DirectoryItem aItem; + sal_Int32 i = aRet.getLength(); + if ( aRet[i-1] == '/' ) + i--; + + if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None ) + aName = aRet; + } + } + else + { + DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" ); + } + } + + if ( !aName.Len() ) + { + ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get(); + if (rTempNameBase_Impl.getLength() == 0) + { + ::rtl::OUString ustrTempDirURL; + ::osl::FileBase::RC rc = ::osl::File::getTempDirURL( + ustrTempDirURL ); + if (rc == ::osl::FileBase::E_None) + rTempNameBase_Impl = ustrTempDirURL; + } + // if no parent or invalid parent : use default directory + DBG_ASSERT( rTempNameBase_Impl.getLength(), "No TempDir!" ); + aName = rTempNameBase_Impl; + ensuredir( aName ); + } + + // Make sure that directory ends with a separator + xub_StrLen i = aName.Len(); + if( i>0 && aName.GetChar(i-1) != '/' ) + aName += '/'; + + return aName; +} + +void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True ) +{ + // add a suitable tempname + // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576 + // ER 13.07.00 why not radix 36 [0-9A-Z] ?!? + const unsigned nRadix = 26; + String aName( rName ); + aName += String::CreateFromAscii( "sv" ); + + rName.Erase(); + static unsigned long u = Time::GetSystemTicks(); + for ( unsigned long nOld = u; ++u != nOld; ) + { + u %= (nRadix*nRadix*nRadix); + String aTmp( aName ); + aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix ); + aTmp += String::CreateFromAscii( ".tmp" ); + + if ( bDir ) + { + FileBase::RC err = Directory::create( aTmp ); + if ( err == FileBase::E_None ) + { + // !bKeep: only for creating a name, not a file or directory + if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None ) + rName = aTmp; + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + } + else + { + DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" ); + File aFile( aTmp ); +#ifdef UNX +/* RW permission for the user only! */ + mode_t old_mode = umask(077); +#endif + FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); +#ifdef UNX +umask(old_mode); +#endif + if ( err == FileBase::E_None ) + { + rName = aTmp; + aFile.close(); + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create files + // but if there is a folder with such name proceed further + + DirectoryItem aTmpItem; + FileStatus aTmpStatus( FileStatusMask_Type ); + if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None + || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None + || aTmpStatus.getFileType() != FileStatus::Directory ) + break; + } + } + } +} + +void lcl_createName(TempFile_Impl& _rImpl,const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory) +{ + _rImpl.bIsDirectory = bDirectory; + + // get correct directory + String aName = ConstructTempDir_Impl( pParent ); + + sal_Bool bUseNumber = _bStartWithZero; + // now use special naming scheme ( name takes leading chars and an index counting up from zero + aName += rLeadingChars; + for ( sal_Int32 i=0;; i++ ) + { + String aTmp( aName ); + if ( bUseNumber ) + aTmp += String::CreateFromInt32( i ); + bUseNumber = sal_True; + if ( pExtension ) + aTmp += *pExtension; + else + aTmp += String::CreateFromAscii( ".tmp" ); + if ( bDirectory ) + { + FileBase::RC err = Directory::create( aTmp ); + if ( err == FileBase::E_None ) + { + _rImpl.aName = aTmp; + break; + } + else if ( err != FileBase::E_EXIST ) + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + else + { + File aFile( aTmp ); +#ifdef UNX +/* RW permission for the user only! */ + mode_t old_mode = umask(077); +#endif + FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); +#ifdef UNX +umask(old_mode); +#endif + if ( err == FileBase::E_None ) + { + _rImpl.aName = aTmp; + aFile.close(); + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create dirs + // but if there is a folder with such name proceed further + + DirectoryItem aTmpItem; + FileStatus aTmpStatus( FileStatusMask_Type ); + if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None + || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None + || aTmpStatus.getFileType() != FileStatus::Directory ) + break; + } + } + if ( !_bStartWithZero ) + aTmp += String::CreateFromInt32( i ); + } +} + + +String TempFile::CreateTempName( const String* pParent ) +{ + // get correct directory + String aName = ConstructTempDir_Impl( pParent ); + + // get TempFile name with default naming scheme + CreateTempName_Impl( aName, sal_False ); + + // convert to file URL + rtl::OUString aTmp; + if ( aName.Len() ) + FileBase::getSystemPathFromFileURL( aName, aTmp ); + return aTmp; +} + +TempFile::TempFile( const String* pParent, sal_Bool bDirectory ) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + pImp->bIsDirectory = bDirectory; + + // get correct directory + pImp->aName = ConstructTempDir_Impl( pParent ); + + // get TempFile with default naming scheme + CreateTempName_Impl( pImp->aName, sal_True, bDirectory ); +} + +TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + lcl_createName(*pImp,rLeadingChars,sal_True, pExtension, pParent, bDirectory); +} +TempFile::TempFile( const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + lcl_createName(*pImp,rLeadingChars,_bStartWithZero, pExtension, pParent, bDirectory); +} + +TempFile::~TempFile() +{ + delete pImp->pStream; + if ( bKillingFileEnabled ) + { + if ( pImp->bIsDirectory ) + { + // at the moment no recursiv algorithm present + Directory::remove( pImp->aName ); + } + else + { + File::remove( pImp->aName ); + } + } + + delete pImp; +} + +sal_Bool TempFile::IsValid() const +{ + return pImp->aName.Len() != 0; +} + +String TempFile::GetFileName() const +{ + rtl::OUString aTmp; + FileBase::getSystemPathFromFileURL( pImp->aName, aTmp ); + return aTmp; +} + +String TempFile::GetURL() const +{ + if ( !pImp->aURL.Len() ) + { + String aTmp; + LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp ); + pImp->aURL = aTmp; + } + + return pImp->aURL; +} + +SvStream* TempFile::GetStream( StreamMode eMode ) +{ + if ( !pImp->pStream ) + { + if ( GetURL().Len() ) + pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ ); + else + pImp->pStream = new SvMemoryStream( eMode ); + } + + return pImp->pStream; +} + +void TempFile::CloseStream() +{ + if ( pImp->pStream ) + { + delete pImp->pStream; + pImp->pStream = NULL; + } +} + +String TempFile::SetTempNameBaseDirectory( const String &rBaseName ) +{ + if( !rBaseName.Len() ) + return String(); + + rtl::OUString aUnqPath( rBaseName ); + + // remove trailing slash + if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) ) + aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 ); + + // try to create the directory + sal_Bool bRet = sal_False; + osl::FileBase::RC err = osl::Directory::create( aUnqPath ); + if ( err != FileBase::E_None && err != FileBase::E_EXIST ) + // perhaps parent(s) don't exist + bRet = ensuredir( aUnqPath ); + else + bRet = sal_True; + + // failure to create base directory means returning an empty string + rtl::OUString aTmp; + if ( bRet ) + { + // append own internal directory + bRet = sal_True; + ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get(); + rTempNameBase_Impl = rBaseName; + rTempNameBase_Impl += String( '/' ); + + TempFile aBase( NULL, sal_True ); + if ( aBase.IsValid() ) + // use it in case of success + rTempNameBase_Impl = aBase.pImp->aName; + + // return system path of used directory + FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp ); + } + + return aTmp; +} + +String TempFile::GetTempNameBaseDirectory() +{ + const ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get(); + if ( !rTempNameBase_Impl.getLength() ) + return String(); + + rtl::OUString aTmp; + FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp ); + return aTmp; +} + +} diff --git a/unotools/source/ucbhelper/ucbhelper.cxx b/unotools/source/ucbhelper/ucbhelper.cxx new file mode 100644 index 000000000000..2b301efc4e52 --- /dev/null +++ b/unotools/source/ucbhelper/ucbhelper.cxx @@ -0,0 +1,889 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ucbhelper.cxx,v $ + * $Revision: 1.24 $ + * + * 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_unotools.hxx" + +#include "unotools/ucbhelper.hxx" +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContentIdentifierFactory.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/ContentInfoAttribute.hpp> +#include <com/sun/star/ucb/XContentCreator.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/container/XChild.hpp> +#ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_ +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#endif +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include <comphelper/processfactory.hxx> +#include <osl/file.hxx> + +#include <tools/wldcrd.hxx> +#include <tools/ref.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <tools/datetime.hxx> +#include <ucbhelper/contentbroker.hxx> + +#include "unotools/localfilehelper.hxx" + +using namespace ucbhelper; +using namespace com::sun::star; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::task; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace rtl; +using namespace comphelper; +using namespace osl; + +DECLARE_LIST( StringList_Impl, OUString* ) + +#define CONVERT_DATETIME( aUnoDT, aToolsDT ) \ + aToolsDT = DateTime( Date( aUnoDT.Day, aUnoDT.Month, aUnoDT.Year ), \ + Time( aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, aUnoDT.HundredthSeconds ) ); + +namespace utl +{ + +sal_Bool UCBContentHelper::Transfer_Impl( const String& rSource, const String& rDest, sal_Bool bMoveData, sal_Int32 nNameClash ) +{ + sal_Bool bRet = sal_True, bKillSource = sal_False; + INetURLObject aSourceObj( rSource ); + DBG_ASSERT( aSourceObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + INetURLObject aDestObj( rDest ); + DBG_ASSERT( aDestObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + if ( bMoveData && aSourceObj.GetProtocol() != aDestObj.GetProtocol() ) + { + bMoveData = sal_False; + bKillSource = sal_True; + } + String aName = aDestObj.getName(); + aDestObj.removeSegment(); + aDestObj.setFinalSlash(); + + try + { + Content aDestPath( aDestObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + uno::Reference< ::com::sun::star::ucb::XCommandInfo > xInfo = aDestPath.getCommands(); + OUString aTransferName = OUString::createFromAscii( "transfer" ); + if ( xInfo->hasCommandByName( aTransferName ) ) + { + aDestPath.executeCommand( aTransferName, makeAny( + ::com::sun::star::ucb::TransferInfo( bMoveData, aSourceObj.GetMainURL( INetURLObject::NO_DECODE ), aName, nNameClash ) ) ); + } + else + { + DBG_ERRORFILE( "transfer command not available" ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + bRet = sal_False; + } + catch( ::com::sun::star::uno::Exception& ) + { + bRet = sal_False; + } + + if ( bKillSource ) + UCBContentHelper::Kill( rSource ); + + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::IsDocument( const String& rContent ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + bRet = aCnt.isDocument(); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + } + catch( ::com::sun::star::ucb::IllegalIdentifierException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ContentCreationException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +Any UCBContentHelper::GetProperty( const String& rContent, const ::rtl::OUString& rName ) +{ + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + return aCnt.getPropertyValue( rName ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + } + catch( ::com::sun::star::ucb::IllegalIdentifierException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ContentCreationException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + } + + return Any(); +} + +sal_Bool UCBContentHelper::IsFolder( const String& rContent ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + bRet = aCnt.isFolder(); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + } + catch( ::com::sun::star::ucb::IllegalIdentifierException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ContentCreationException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::GetTitle( const String& rContent, String& rTitle ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + OUString aTemp; + if ( aCnt.getPropertyValue( OUString::createFromAscii( "Title" ) ) >>= aTemp ) + { + rTitle = String( aTemp ); + bRet = sal_True; + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::Kill( const String& rContent ) +{ + sal_Bool bRet = sal_True; + INetURLObject aDeleteObj( rContent ); + DBG_ASSERT( aDeleteObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + try + { + Content aCnt( aDeleteObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + aCnt.executeCommand( OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + bRet = sal_False; + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + bRet = sal_False; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +Sequence < OUString > UCBContentHelper::GetFolderContents( const String& rFolder, sal_Bool bFolder, sal_Bool bSorted ) +{ + StringList_Impl* pFiles = NULL; + INetURLObject aFolderObj( rFolder ); + DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps( bSorted ? 2 : 1 ); + OUString* pProps = aProps.getArray(); + pProps[0] = OUString::createFromAscii( "Title" ); + if ( bSorted ) + pProps[1] = OUString::createFromAscii( "IsFolder" ); + + try + { + ResultSetInclude eInclude = bFolder ? INCLUDE_FOLDERS_AND_DOCUMENTS : INCLUDE_DOCUMENTS_ONLY; + if ( !bSorted ) + { + xResultSet = aCnt.createCursor( aProps, eInclude ); + } + else + { + uno::Reference< com::sun::star::ucb::XDynamicResultSet > xDynResultSet; + xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude ); + + uno::Reference < com::sun::star::ucb::XAnyCompareFactory > xFactory; + uno::Reference < XMultiServiceFactory > xMgr = getProcessServiceFactory(); + uno::Reference < com::sun::star::ucb::XSortedDynamicResultSetFactory > xSRSFac( + xMgr->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.ucb.SortedDynamicResultSetFactory") ), UNO_QUERY ); + + Sequence< com::sun::star::ucb::NumberedSortingInfo > aSortInfo( 2 ); + com::sun::star::ucb::NumberedSortingInfo* pInfo = aSortInfo.getArray(); + pInfo[ 0 ].ColumnIndex = 2; + pInfo[ 0 ].Ascending = sal_False; + pInfo[ 1 ].ColumnIndex = 1; + pInfo[ 1 ].Ascending = sal_True; + + uno::Reference< com::sun::star::ucb::XDynamicResultSet > xDynamicResultSet; + xDynamicResultSet = + xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xFactory ); + if ( xDynamicResultSet.is() ) + { + xResultSet = xDynamicResultSet->getStaticResultSet(); + } + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + // folder not exists? + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( xResultSet.is() ) + { + pFiles = new StringList_Impl; + uno::Reference< com::sun::star::ucb::XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + try + { + while ( xResultSet->next() ) + { + OUString aId = xContentAccess->queryContentIdentifierString(); + OUString* pFile = new OUString( aId ); + pFiles->Insert( pFile, LIST_APPEND ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + } + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( pFiles ) + { + ULONG nCount = pFiles->Count(); + Sequence < OUString > aRet( nCount ); + OUString* pRet = aRet.getArray(); + for ( ULONG i = 0; i < nCount; ++i ) + { + OUString* pFile = pFiles->GetObject(i); + pRet[i] = *( pFile ); + delete pFile; + } + delete pFiles; + return aRet; + } + else + return Sequence < OUString > (); +} + +// ----------------------------------------------------------------------- + +Sequence < OUString > UCBContentHelper::GetResultSet( const String& rURL ) +{ + StringList_Impl* pList = NULL; + try + { + Content aCnt( rURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + uno::Reference< XResultSet > xResultSet; + uno::Reference< com::sun::star::ucb::XDynamicResultSet > xDynResultSet; + Sequence< OUString > aProps(3); + OUString* pProps = aProps.getArray(); + pProps[0] = OUString::createFromAscii( "Title" ); + pProps[1] = OUString::createFromAscii( "ContentType" ); + // TODO: can be optimized, property never used: + pProps[2] = OUString::createFromAscii( "IsFolder" ); + + try + { + xDynResultSet = aCnt.createDynamicCursor( aProps, INCLUDE_FOLDERS_AND_DOCUMENTS ); + if ( xDynResultSet.is() ) + xResultSet = xDynResultSet->getStaticResultSet(); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( xResultSet.is() ) + { + pList = new StringList_Impl; + uno::Reference< com::sun::star::sdbc::XRow > xRow( xResultSet, UNO_QUERY ); + uno::Reference< com::sun::star::ucb::XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + String aTitle( xRow->getString(1) ); + String aType( xRow->getString(2) ); + String aRow = aTitle; + aRow += '\t'; + aRow += aType; + aRow += '\t'; + aRow += String( xContentAccess->queryContentIdentifierString() ); + OUString* pRow = new OUString( aRow ); + pList->Insert( pRow, LIST_APPEND ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + } + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( pList ) + { + ULONG nCount = pList->Count(); + Sequence < OUString > aRet( nCount ); + OUString* pRet = aRet.getArray(); + for ( ULONG i = 0; i < nCount; ++i ) + { + OUString* pEntry = pList->GetObject(i); + pRet[i] = *( pEntry ); + delete pEntry; + } + delete pList; + return aRet; + } + else + return Sequence < OUString > (); +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::CopyTo( const String& rSource, const String& rDest ) +{ + return Transfer_Impl( rSource, rDest, sal_False, NameClash::ERROR ); +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::MoveTo( const String& rSource, const String& rDest, sal_Int32 nNameClash ) +{ + return Transfer_Impl( rSource, rDest, sal_True, nNameClash ); +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::CanMakeFolder( const String& rFolder ) +{ + try + { + Content aCnt( rFolder, uno::Reference< XCommandEnvironment > () ); + uno::Reference< XContentCreator > xCreator = uno::Reference< XContentCreator >( aCnt.get(), UNO_QUERY ); + if ( !xCreator.is() ) + return sal_False; + + Sequence< ContentInfo > aInfo = xCreator->queryCreatableContentsInfo(); + sal_Int32 nCount = aInfo.getLength(); + if ( nCount == 0 ) + return sal_False; + + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + // Simply look for the first KIND_FOLDER... + const ContentInfo & rCurr = aInfo[i]; + if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER ) + return sal_True; + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) {} + catch( RuntimeException& ) {} + catch( Exception& ) {} + + return sal_False; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::MakeFolder( const String& rFolder, sal_Bool bNewOnly ) +{ + INetURLObject aURL( rFolder ); + DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + String aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + aURL.removeSegment(); + Content aCnt; + Content aNew; + uno::Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + uno::Reference< XInteractionHandler > xInteractionHandler = uno::Reference< XInteractionHandler > ( + xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uui.InteractionHandler") ) ), UNO_QUERY ); + if ( Content::create( aURL.GetMainURL( INetURLObject::NO_DECODE ), new CommandEnvironment( xInteractionHandler, uno::Reference< XProgressHandler >() ), aCnt ) ) + return MakeFolder( aCnt, aTitle, aNew, bNewOnly ); + else + return sal_False; +} + +sal_Bool UCBContentHelper::MakeFolder( Content& aCnt, const String& aTitle, Content& rNew, sal_Bool bNewOnly ) +{ + sal_Bool bAlreadyExists = sal_False; + + try + { + uno::Reference< XContentCreator > xCreator( aCnt.get(), UNO_QUERY ); + if ( !xCreator.is() ) + return sal_False; + + Sequence< ContentInfo > aInfo = xCreator->queryCreatableContentsInfo(); + sal_Int32 nCount = aInfo.getLength(); + if ( nCount == 0 ) + return sal_False; + + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + // Simply look for the first KIND_FOLDER... + const ContentInfo & rCurr = aInfo[i]; + if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER ) + { + // Make sure the only required bootstrap property is "Title", + const Sequence< Property > & rProps = rCurr.Properties; + if ( rProps.getLength() != 1 ) + continue; + + if ( !rProps[ 0 ].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + continue; + + Sequence<OUString> aNames(1); + OUString* pNames = aNames.getArray(); + pNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ); + Sequence<Any> aValues(1); + Any* pValues = aValues.getArray(); + pValues[0] = makeAny( OUString( aTitle ) ); + + if ( !aCnt.insertNewContent( rCurr.Type, aNames, aValues, rNew ) ) + continue; + + return sal_True; + } + } + } + catch ( InteractiveIOException& r ) + { + if ( r.Code == IOErrorCode_ALREADY_EXISTING ) + { + bAlreadyExists = sal_True; + } + } + catch ( NameClashException& ) + { + bAlreadyExists = sal_True; + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( RuntimeException& ) + { + } + catch( Exception& ) + { + } + + if( bAlreadyExists && !bNewOnly ) + { + INetURLObject aObj( aCnt.getURL() ); + aObj.Append( aTitle ); + rNew = Content( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < XCommandEnvironment >() ); + return sal_True; + } + + return sal_False; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::HasParentFolder( const String& rFolder ) +{ + sal_Bool bRet = sal_False; + try + { + Content aCnt( rFolder, uno::Reference< XCommandEnvironment > () ); + uno::Reference< XChild > xChild( aCnt.get(), UNO_QUERY ); + if ( xChild.is() ) + { + uno::Reference< XContent > xParent( xChild->getParent(), UNO_QUERY ); + if ( xParent.is() ) + { + String aParentURL = String( xParent->getIdentifier()->getContentIdentifier() ); + bRet = ( aParentURL.Len() > 0 && aParentURL != rFolder ); + } + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +ULONG UCBContentHelper::GetSize( const String& rContent ) +{ + ULONG nSize = 0; + sal_Int64 nTemp = 0; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + aCnt.getPropertyValue( OUString::createFromAscii( "Size" ) ) >>= nTemp; + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + nSize = (UINT32)nTemp; + return nSize; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::IsYounger( const String& rIsYoung, const String& rIsOlder ) +{ + DateTime aYoungDate, aOlderDate; + INetURLObject aYoungObj( rIsYoung ); + DBG_ASSERT( aYoungObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + INetURLObject aOlderObj( rIsOlder ); + DBG_ASSERT( aOlderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > aCmdEnv; + Content aYoung( aYoungObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv ); + ::com::sun::star::util::DateTime aTempYoungDate; + aYoung.getPropertyValue( OUString::createFromAscii( "DateModified" ) ) >>= aTempYoungDate; + CONVERT_DATETIME( aTempYoungDate, aYoungDate ); + Content aOlder( aOlderObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv ); + ::com::sun::star::util::DateTime aTempOlderDate; + aOlder.getPropertyValue( OUString::createFromAscii( "DateModified" ) ) >>= aTempOlderDate; + CONVERT_DATETIME( aTempOlderDate, aOlderDate ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + return ( aYoungDate > aOlderDate ); +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::Find( const String& rFolder, const String& rName, String& rFile, BOOL bAllowWildCards ) +{ + BOOL bWild = bAllowWildCards && ( rName.Search( '*' ) != STRING_NOTFOUND || rName.Search( '?' ) != STRING_NOTFOUND ); + + sal_Bool bRet = sal_False; + + // get a list of URLs for all children of rFolder + Sequence< ::rtl::OUString > aFiles = GetFolderContents( rFolder, sal_False ); + + const ::rtl::OUString* pFiles = aFiles.getConstArray(); + UINT32 i, nCount = aFiles.getLength(); + for ( i = 0; i < nCount; ++i ) + { + // get the last name of the URLs and compare it with rName + INetURLObject aFileObject( pFiles[i] ); + String aFile = aFileObject.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).toAsciiLowerCase(); + if ( (bWild && WildCard( rName ).Matches( aFile )) || aFile == rName ) + { + // names match + rFile = aFileObject.GetMainURL( INetURLObject::NO_DECODE ); + bRet = sal_True; + break; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::Exists( const String& rURL ) +{ + + String sObjectPhysicalName; + sal_Bool bIsLocalFile = ::utl::LocalFileHelper::ConvertURLToPhysicalName( rURL, sObjectPhysicalName ); + // try to create a directory entry for the URL given + if ( bIsLocalFile ) + { + ::rtl::OUString sIn( sObjectPhysicalName ), sOut; + if ( osl_File_E_None == osl_getFileURLFromSystemPath( sIn.pData, &sOut.pData ) ) + { + // #106526 osl_getDirectoryItem is an existence check + // no further osl_getFileStatus call necessary + DirectoryItem aItem; + return (FileBase::E_None == DirectoryItem::get(sOut, aItem)); + } + return sal_False; + } + + // divide URL into folder and name part + sal_Bool bRet = sal_False; + INetURLObject aObj( rURL ); + ::rtl::OUString aFileName = aObj.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).toAsciiLowerCase(); + aObj.removeSegment(); + aObj.removeFinalSlash(); + + // get a list of URLs for all children of rFolder + Sequence< ::rtl::OUString > aFiles = GetFolderContents( aObj.GetMainURL( INetURLObject::NO_DECODE ), sal_True, sal_False ); + + const ::rtl::OUString* pFiles = aFiles.getConstArray(); + UINT32 i, nCount = aFiles.getLength(); + for ( i = 0; i < nCount; ++i ) + { + // get the last name of the URLs and compare it with rName + INetURLObject aFileObject( pFiles[i] ); + ::rtl::OUString aFile = aFileObject.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).toAsciiLowerCase(); + if ( aFile == aFileName ) + { + // names match + bRet = sal_True; + break; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::FindInPath( const String& rPath, const String& rName, String& rFile, char cDelim, BOOL bAllowWildCards ) +{ + // extract the single folder names from the path variable and try to find the file in one of these folders + USHORT nTokenCount = rPath.GetTokenCount( cDelim ); + for ( USHORT nToken = 0; nToken < nTokenCount; ++nToken ) + { + String aPath = rPath.GetToken( nToken, cDelim ); + if ( Find( aPath, rName, rFile, bAllowWildCards ) ) + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::IsSubPath( const ::rtl::OUString& rPath, const ::rtl::OUString& rSubfolderCandidate, const uno::Reference< ::com::sun::star::ucb::XContentProvider >& xProv ) +{ + sal_Bool bResult = sal_False; + + uno::Reference< ::com::sun::star::ucb::XContentProvider > xContentProvider = xProv; + + // the comparing is done in the following way: + // - first compare in case sensitive way + // - if name are different try a fallback comparing inf case insensitive way + // - if the last comparing succeeded get casepreserving normalized names for the files and compare them + // ( the second step is required because retrieving of the normalized names might be very expensive in some cases ) + + INetURLObject aCandidate( rSubfolderCandidate ); + INetURLObject aCandidateLowCase( rSubfolderCandidate.toAsciiLowerCase() ); // will be used for case insensitive comparing + INetURLObject aParentFolder( rPath ); + INetURLObject aParentFolderLowCase( rPath.toAsciiLowerCase() ); // will be used for case insensitive comparing + + if ( aCandidate.GetProtocol() == aParentFolder.GetProtocol() ) + { + if ( !xContentProvider.is() ) + { + ::ucbhelper::ContentBroker* pBroker = NULL; + if ( aCandidate.GetProtocol() == INET_PROT_FILE ) + { + pBroker = ::ucbhelper::ContentBroker::get(); + if ( pBroker ) + xContentProvider = pBroker->getContentProviderInterface(); + } + } + + INetURLObject aLastTmpObj; + do + { + if ( aParentFolder == aCandidate ) + { + // if case sensitive comparing succeeded there is no need for additional checks + bResult = sal_True; + } + else if ( xContentProvider.is() && aParentFolderLowCase == aCandidateLowCase ) + { + // the comparing was done using caseinsensitive way + // the case sensitive comparing have failed already + // the normalized urls must be retrieved + try + { + uno::Reference< ::com::sun::star::ucb::XContent > xSecCont = + xContentProvider->queryContent( + uno::Reference< ::com::sun::star::ucb::XContentIdentifierFactory >( + xContentProvider, ::com::sun::star::uno::UNO_QUERY_THROW )->createContentIdentifier( + aParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) ); + + uno::Reference< ::com::sun::star::ucb::XContent > xLocCont = + xContentProvider->queryContent( + uno::Reference< ::com::sun::star::ucb::XContentIdentifierFactory >( + xContentProvider, ::com::sun::star::uno::UNO_QUERY_THROW )->createContentIdentifier( + aCandidate.GetMainURL( INetURLObject::NO_DECODE ) ) ); + + if ( !xSecCont.is() || !xLocCont.is() ) + throw ::com::sun::star::uno::RuntimeException(); + + ::rtl::OUString aSecNormStr; + ::rtl::OUString aLocNormStr; + + bResult = + ( ( uno::Reference< ::com::sun::star::ucb::XCommandProcessor >( + xSecCont, ::com::sun::star::uno::UNO_QUERY_THROW )->execute( + ::com::sun::star::ucb::Command( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCasePreservingURL" ) ), + -1, + ::com::sun::star::uno::Any() ), + 0, + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ) + >>= aSecNormStr ) + && ( uno::Reference< ::com::sun::star::ucb::XCommandProcessor >( + xLocCont, ::com::sun::star::uno::UNO_QUERY_THROW )->execute( + ::com::sun::star::ucb::Command( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCasePreservingURL" ) ), + -1, + ::com::sun::star::uno::Any() ), + 0, + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ) + >>= aLocNormStr ) + && aLocNormStr.equals( aSecNormStr ) ); + } + catch( ::com::sun::star::uno::Exception& ) + {} + } + + // INetURLObject::removeSegment sometimes return true without exchanging URL, + // for example in case of "file:///" + aLastTmpObj = aCandidate; + + } while( aCandidate.removeSegment() && aCandidateLowCase.removeSegment() && aCandidate != aLastTmpObj && !bResult ); + } + + return bResult; +} + +} // namespace utl + diff --git a/unotools/source/ucbhelper/ucblockbytes.cxx b/unotools/source/ucbhelper/ucblockbytes.cxx new file mode 100644 index 000000000000..45ed6e728033 --- /dev/null +++ b/unotools/source/ucbhelper/ucblockbytes.cxx @@ -0,0 +1,1749 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ucblockbytes.cxx,v $ + * $Revision: 1.60 $ + * + * 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_unotools.hxx" + +#include <unotools/ucblockbytes.hxx> +#include <comphelper/processfactory.hxx> +#include <salhelper/condition.hxx> +#ifndef _OSL_THREAD_HXX_ +#include <osl/thread.hxx> +#endif +#include <tools/urlobj.hxx> +#include <ucbhelper/interactionrequest.hxx> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_ +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#endif +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <com/sun/star/ucb/DocumentHeaderField.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/PostCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> +#include <tools/inetmsg.hxx> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <comphelper/storagehelper.hxx> + +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/content.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + + +namespace utl +{ + +/** + Helper class for getting a XInputStream when opening a content + */ +class UcbDataSink_Impl : public ::cppu::WeakImplHelper2< XActiveDataControl, XActiveDataSink > +{ + UcbLockBytesRef m_xLockBytes; + +public: + UcbDataSink_Impl( UcbLockBytes* pLockBytes ) + : m_xLockBytes( pLockBytes ) + {} + + SvLockBytes* getLockBytes (void) + { return m_xLockBytes; } + + // XActiveDataControl. + virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL start (void) throw(RuntimeException) {} + virtual void SAL_CALL terminate (void) throw(RuntimeException) + { m_xLockBytes->terminate_Impl(); } + + // XActiveDataSink. + virtual void SAL_CALL setInputStream ( const Reference<XInputStream> &rxInputStream) throw(RuntimeException) + { m_xLockBytes->setInputStream_Impl (rxInputStream); } + virtual Reference<XInputStream> SAL_CALL getInputStream (void) throw(RuntimeException) + { return m_xLockBytes->getInputStream_Impl(); } +}; + +/** + Helper class for getting a XStream when opening a content + */ +class UcbStreamer_Impl : public ::cppu::WeakImplHelper2< XActiveDataStreamer, XActiveDataControl > +{ + Reference < XStream > m_xStream; + UcbLockBytesRef m_xLockBytes; + +public: + + UcbStreamer_Impl( UcbLockBytes* pLockBytes ) + : m_xLockBytes( pLockBytes ) + {} + + // XActiveDataControl. + virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL start (void) throw(RuntimeException) {} + virtual void SAL_CALL terminate (void) throw(RuntimeException) + { m_xLockBytes->terminate_Impl(); } + + // XActiveDataStreamer + virtual void SAL_CALL setStream( const Reference< XStream >& aStream ) throw(RuntimeException) + { m_xStream = aStream; m_xLockBytes->setStream_Impl( aStream ); } + virtual Reference< XStream > SAL_CALL getStream() throw(RuntimeException) + { return m_xStream; } +}; + +/** + Helper class for progress handling while executing UCB commands + */ +class ProgressHandler_Impl: public ::cppu::WeakImplHelper1< XProgressHandler > +{ + Link m_aProgress; + +public: + ProgressHandler_Impl( const Link& rLink ) + : m_aProgress( rLink ) + {} + // XProgressHandler + virtual void SAL_CALL push(const Any & /*rStatus*/) throw (RuntimeException) {} + virtual void SAL_CALL pop() throw (RuntimeException) {} + virtual void SAL_CALL update(const Any & /*rStatus*/) throw (RuntimeException) + { if ( m_aProgress.IsSet() ) m_aProgress.Call( 0 ); } +}; + +/** + Helper class for managing interactions and progress when executing UCB commands + */ +class UcbTaskEnvironment : public ::cppu::WeakImplHelper1< XCommandEnvironment > +{ + Reference< XInteractionHandler > m_xInteractionHandler; + Reference< XProgressHandler > m_xProgressHandler; + +public: + UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler, + const Reference< XProgressHandler>& rxProgressHandler ) + : m_xInteractionHandler( rxInteractionHandler ) + , m_xProgressHandler( rxProgressHandler ) + {} + + + virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() throw (RuntimeException) + { return m_xInteractionHandler; } + + virtual Reference<XProgressHandler> SAL_CALL getProgressHandler() throw (RuntimeException) + { return m_xProgressHandler; } +}; + + +/** + Helper class for property change notifies when executing UCB commands +*/ +class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper1< XPropertiesChangeListener > +{ +public: + UcbLockBytesRef m_xLockBytes; + + UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef ) + : m_xLockBytes( rRef ) + {} + + virtual void SAL_CALL disposing ( const EventObject &/*rEvent*/) throw(RuntimeException) {} + virtual void SAL_CALL propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException); +}; + +void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException) +{ + sal_Int32 i, n = rEvent.getLength(); + for (i = 0; i < n; i++) + { + PropertyChangeEvent evt (rEvent[i]); + if (evt.PropertyName == ::rtl::OUString::createFromAscii ("DocumentHeader")) + { + Sequence<DocumentHeaderField> aHead; + if (evt.NewValue >>= aHead) + { + sal_Int32 k, m = aHead.getLength(); + for (k = 0; k < m; k++) + { + String aName( aHead[k].Name ); + String aValue( aHead[k].Value ); + + if (aName.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL) + { + DateTime aExpires (0, 0); + if (INetRFC822Message::ParseDateField (aValue, aExpires)) + { + aExpires.ConvertToLocalTime(); + m_xLockBytes->SetExpireDate_Impl( aExpires ); + } + } + } + } + + m_xLockBytes->SetStreamValid_Impl(); + } + else if (evt.PropertyName == rtl::OUString::createFromAscii ("PresentationURL")) + { + ::rtl::OUString aUrl; + if (evt.NewValue >>= aUrl) + { + ::rtl::OUString aBad (::rtl::OUString::createFromAscii ("private:")); + if (!(aUrl.compareTo (aBad, aBad.getLength()) == 0)) + { + // URL changed (Redirection). + m_xLockBytes->SetRealURL_Impl( aUrl ); + } + } + } + else if (evt.PropertyName == ::rtl::OUString::createFromAscii ("MediaType")) + { + ::rtl::OUString aContentType; + if (evt.NewValue >>= aContentType) + m_xLockBytes->SetContentType_Impl( aContentType ); + } + } +} + + + +class Moderator + : public osl::Thread +{ + // usage restriction: + // It might be possible, that the call to the interactionhandler and/or + // progresshandler is done asynchrounsly, while the 'execute' simply + // returns. This would imply that these class must be refcounted !!! + +public: + + Moderator( + Reference < XContent >& xContent, + Reference < XInteractionHandler >& xInteract, + Reference < XProgressHandler >& xProgress, + const Command& rArg + ) + throw( + ContentCreationException, + RuntimeException + ); + + ~Moderator(); + + + enum ResultType { + NORESULT, + + INTERACTIONREQUEST, // reply expected + + PROGRESSPUSH, + PROGRESSUPDATE, + PROGRESSPOP, + + INPUTSTREAM, + STREAM, + + RESULT, + TIMEDOUT, + COMMANDABORTED, + COMMANDFAILED, + INTERACTIVEIO, + UNSUPPORTED, + GENERAL + }; + + + class ConditionRes + : public salhelper::Condition + { + public: + + ConditionRes(osl::Mutex& aMutex,Moderator& aModerator) + : salhelper::Condition(aMutex), + m_aModerator(aModerator) + { + } + + protected: + + bool applies() const { + return m_aModerator.m_aResultType != NORESULT; + } + + private: + + Moderator& m_aModerator; + }; + + + struct Result { + ResultType type; + Any result; + sal_Int32 ioErrorCode; + }; + + + Result getResult(const sal_uInt32 milliSec); + + + enum ReplyType { + NOREPLY, + EXIT, + RETRY, + REQUESTHANDLED + }; + + + class ConditionRep + : public salhelper::Condition + { + public: + + ConditionRep(osl::Mutex& aMutex,Moderator& aModerator) + : salhelper::Condition(aMutex), + m_aModerator(aModerator) + { + } + + protected: + + bool applies() const { + return m_aModerator.m_aReplyType != NOREPLY; + } + + private: + + Moderator& m_aModerator; + }; + + void setReply(ReplyType); + + + void handle( const Reference<XInteractionRequest >& Request ); + + void push( const Any& Status ); + + void update( const Any& Status ); + + void pop( ); + + void setStream(const Reference< XStream >& aStream); + + void setInputStream(const Reference<XInputStream> &rxInputStream); + + +protected: + + virtual void SAL_CALL run(); + + virtual void SAL_CALL onTerminated(); + +private: + + osl::Mutex m_aMutex; + + friend class ConditionRes; + + ConditionRes m_aRes; + ResultType m_aResultType; + sal_Int32 m_nIOErrorCode; + Any m_aResult; + + friend class ConditionRep; + + ConditionRep m_aRep; + ReplyType m_aReplyType; + + Command m_aArg; + ::ucbhelper::Content m_aContent; +}; + + +class ModeratorsActiveDataStreamer + : public ::cppu::WeakImplHelper1<XActiveDataStreamer> +{ +public: + + ModeratorsActiveDataStreamer(Moderator &theModerator); + + ~ModeratorsActiveDataStreamer(); + + // XActiveDataStreamer + virtual void SAL_CALL + setStream( + const Reference< XStream >& aStream + ) + throw( + RuntimeException + ); + + virtual Reference<XStream> SAL_CALL + getStream ( + void + ) throw( + RuntimeException + ) + { + osl::MutexGuard aGuard(m_aMutex); + return m_xStream; + } + + +private: + + Moderator& m_aModerator; + + osl::Mutex m_aMutex; + Reference<XStream> m_xStream; +}; + + + +class ModeratorsActiveDataSink + : public ::cppu::WeakImplHelper1<XActiveDataSink> +{ +public: + + ModeratorsActiveDataSink(Moderator &theModerator); + + ~ModeratorsActiveDataSink(); + + // XActiveDataSink. + virtual void SAL_CALL + setInputStream ( + const Reference<XInputStream> &rxInputStream + ) + throw( + RuntimeException + ); + + virtual Reference<XInputStream> SAL_CALL + getInputStream ( + void + ) throw( + RuntimeException + ) + { + osl::MutexGuard aGuard(m_aMutex); + return m_xStream; + } + + +private: + + Moderator& m_aModerator; + osl::Mutex m_aMutex; + Reference<XInputStream> m_xStream; +}; + + + +ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator) + : m_aModerator(theModerator) +{ +} + + +ModeratorsActiveDataSink::~ModeratorsActiveDataSink() +{ +} + +// XActiveDataSink. +void SAL_CALL +ModeratorsActiveDataSink::setInputStream ( + const Reference<XInputStream> &rxInputStream +) + throw( + RuntimeException + ) +{ + m_aModerator.setInputStream(rxInputStream); + osl::MutexGuard aGuard(m_aMutex); + m_xStream = rxInputStream; +} + + +ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer( + Moderator &theModerator +) + : m_aModerator(theModerator) +{ +} + + +ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer() +{ +} + +// XActiveDataStreamer. +void SAL_CALL +ModeratorsActiveDataStreamer::setStream ( + const Reference<XStream> &rxStream +) + throw( + RuntimeException + ) +{ + m_aModerator.setStream(rxStream); + osl::MutexGuard aGuard(m_aMutex); + m_xStream = rxStream; +} + + + +class ModeratorsInteractionHandler + : public ::cppu::WeakImplHelper1<XInteractionHandler> +{ +public: + + ModeratorsInteractionHandler(Moderator &theModerator); + + ~ModeratorsInteractionHandler(); + + virtual void SAL_CALL + handle( const Reference<XInteractionRequest >& Request ) + throw (RuntimeException); + +private: + + Moderator& m_aModerator; +}; + + +class ModeratorsProgressHandler + : public ::cppu::WeakImplHelper1<XProgressHandler> +{ +public: + + ModeratorsProgressHandler(Moderator &theModerator); + + ~ModeratorsProgressHandler(); + + virtual void SAL_CALL push( const Any& Status ) + throw ( + RuntimeException); + + virtual void SAL_CALL update( const Any& Status ) + throw (RuntimeException); + + virtual void SAL_CALL pop( ) + throw (RuntimeException); + + +private: + + Moderator& m_aModerator; +}; + + +ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator &theModerator) + : m_aModerator(theModerator) +{ +} + +ModeratorsProgressHandler::~ModeratorsProgressHandler() +{ +} + + +void SAL_CALL ModeratorsProgressHandler::push( const Any& Status ) + throw ( + RuntimeException) +{ + m_aModerator.push(Status); +} + + +void SAL_CALL ModeratorsProgressHandler::update( const Any& Status ) + throw (RuntimeException) +{ + m_aModerator.update(Status); +} + + +void SAL_CALL ModeratorsProgressHandler::pop( ) + throw (RuntimeException) +{ + m_aModerator.pop(); +} + + + + +ModeratorsInteractionHandler::ModeratorsInteractionHandler( + Moderator &aModerator) + : m_aModerator(aModerator) +{ +} + + +ModeratorsInteractionHandler::~ModeratorsInteractionHandler() +{ +} + + +void SAL_CALL +ModeratorsInteractionHandler::handle( + const Reference<XInteractionRequest >& Request +) + throw ( + RuntimeException + ) +{ + // wakes up the mainthread + m_aModerator.handle(Request); +} + + + + +Moderator::Moderator( + Reference < XContent >& xContent, + Reference < XInteractionHandler >& xInteract, + Reference < XProgressHandler >& xProgress, + const Command& rArg +) + throw( + ::com::sun::star::ucb::ContentCreationException, + ::com::sun::star::uno::RuntimeException + ) + : m_aMutex(), + + m_aRes(m_aMutex,*this), + m_aResultType(NORESULT), + m_nIOErrorCode(0), + m_aResult(), + + m_aRep(m_aMutex,*this), + m_aReplyType(NOREPLY), + + m_aArg(rArg), + m_aContent( + xContent, + new UcbTaskEnvironment( + xInteract.is() ? new ModeratorsInteractionHandler(*this) : 0, + xProgress.is() ? new ModeratorsProgressHandler(*this) : 0 + )) +{ + // now exchange the whole data sink stuff + // with a thread safe version + + Reference<XInterface> *pxSink = NULL; + + PostCommandArgument2 aPostArg; + OpenCommandArgument2 aOpenArg; + + int dec(2); + if(m_aArg.Argument >>= aPostArg) { + pxSink = &aPostArg.Sink; + dec = 0; + } + else if(m_aArg.Argument >>= aOpenArg) { + pxSink = &aOpenArg.Sink; + dec = 1; + } + + if(dec ==2) + throw ContentCreationException(); + + Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY); + if(xActiveSink.is()) + *pxSink = Reference<XInterface>( + (cppu::OWeakObject*)new ModeratorsActiveDataSink(*this)); + + Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY ); + if ( xStreamer.is() ) + *pxSink = Reference<XInterface>( + (cppu::OWeakObject*)new ModeratorsActiveDataStreamer(*this)); + + if(dec == 0) + m_aArg.Argument <<= aPostArg; + else if(dec == 1) + m_aArg.Argument <<= aOpenArg; +} + + +Moderator::~Moderator() +{ +} + + +Moderator::Result Moderator::getResult(const sal_uInt32 milliSec) +{ + Result ret; + try { + salhelper::ConditionWaiter aWaiter(m_aRes,milliSec); + ret.type = m_aResultType; + ret.result = m_aResult; + ret.ioErrorCode = m_nIOErrorCode; + + // reset + m_aResultType = NORESULT; + } + catch(const salhelper::ConditionWaiter::timedout&) + { + ret.type = TIMEDOUT; + } + + return ret; +} + + +void Moderator::setReply(ReplyType aReplyType ) +{ + salhelper::ConditionModifier aMod(m_aRep); + m_aReplyType = aReplyType; +} + + +void Moderator::handle( const Reference<XInteractionRequest >& Request ) +{ + ReplyType aReplyType; + + do { + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = INTERACTIONREQUEST; + m_aResult <<= Request; + } + + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + + // reset + m_aReplyType = NOREPLY; + } + + if(aReplyType == EXIT) { + Sequence<Reference<XInteractionContinuation> > aSeq( + Request->getContinuations()); + for(sal_Int32 i = 0; i < aSeq.getLength(); ++i) { + Reference<XInteractionAbort> aRef(aSeq[i],UNO_QUERY); + if(aRef.is()) { + aRef->select(); + } + } + + // resignal the exitcondition + setReply(EXIT); + break; + } + } while(aReplyType != REQUESTHANDLED); +} + + + +void Moderator::push( const Any& Status ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSPUSH; + m_aResult = Status; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::update( const Any& Status ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSUPDATE; + m_aResult = Status; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::pop( ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSPOP; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::setStream(const Reference< XStream >& aStream) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = STREAM; + m_aResult <<= aStream; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = INPUTSTREAM; + m_aResult <<= rxInputStream; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + + +void SAL_CALL Moderator::run() +{ + ResultType aResultType; + Any aResult; + sal_Int32 nIOErrorCode = 0; + + try + { + aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument); + aResultType = RESULT; + } + catch ( CommandAbortedException ) + { + aResultType = COMMANDABORTED; + } + catch ( CommandFailedException ) + { + aResultType = COMMANDFAILED; + } + catch ( InteractiveIOException& r ) + { + nIOErrorCode = r.Code; + aResultType = INTERACTIVEIO; + } + catch ( UnsupportedDataSinkException& ) + { + aResultType = UNSUPPORTED; + } + catch ( Exception ) + { + aResultType = GENERAL; + } + + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = aResultType; + m_aResult = aResult; + m_nIOErrorCode = nIOErrorCode; + } +} + + + +void SAL_CALL Moderator::onTerminated() +{ + { + salhelper::ConditionWaiter aWaiter(m_aRep); + } + delete this; +} + + +/** + Function for opening UCB contents synchronously, + but with handled timeout; +*/ + +static sal_Bool _UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ); + + +static sal_Bool UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ) +{ + // http protocol must be handled in a special way: + // during the opening process the input stream may change + // only the last inputstream after notifying the document + // headers is valid + + Reference<XContentIdentifier> xContId( + xContent.is() ? xContent->getIdentifier() : 0 ); + + rtl::OUString aScheme; + if(xContId.is()) + aScheme = xContId->getContentProviderScheme(); + + // now determine wether we use a timeout or not; + if( ! aScheme.equalsIgnoreAsciiCaseAscii("http") && + ! aScheme.equalsIgnoreAsciiCaseAscii("https") && + ! aScheme.equalsIgnoreAsciiCaseAscii("vnd.sun.star.webdav") && + ! aScheme.equalsIgnoreAsciiCaseAscii("ftp")) + return _UCBOpenContentSync( + xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler); + + if ( (aScheme.compareToAscii( "http" ) != COMPARE_EQUAL) || + (aScheme.compareToAscii( "https" ) != COMPARE_EQUAL) ) + xLockBytes->SetStreamValid_Impl(); + + Reference< XPropertiesChangeListener > xListener; + Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY); + if(xProps.is()) { + xListener = + new UcbPropertiesChangeListener_Impl(xLockBytes); + xProps->addPropertiesChangeListener( + Sequence< ::rtl::OUString >(), + xListener); + } + + Any aResult; + bool bException(false); + bool bAborted(false); + bool bResultAchieved(false); + + Moderator* pMod = 0; + try { + pMod = new Moderator(xContent,xInteract,xProgress,rArg); + pMod->create(); + } catch(const ContentCreationException&) { + bResultAchieved = bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + sal_uInt32 nTimeout(5000); // initially 5000 milliSec + while(!bResultAchieved) { + + Moderator::Result res; + // try to get the result for with timeout + res = pMod->getResult(nTimeout); + + switch(res.type) { + case Moderator::PROGRESSPUSH: + { + if(xProgress.is()) + xProgress->push(res.result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::PROGRESSUPDATE: + { + if(xProgress.is()) + xProgress->update(res.result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::PROGRESSPOP: + { + if(xProgress.is()) + xProgress->pop(); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::STREAM: + { + Reference<XStream> result; + if(res.result >>= result) { + Reference < XActiveDataStreamer > xStreamer( + xSink, UNO_QUERY + ); + + if(xStreamer.is()) + xStreamer->setStream(result); + } + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::INPUTSTREAM: + { + Reference<XInputStream> result; + res.result >>= result; + Reference < XActiveDataSink > xActiveSink( + xSink, UNO_QUERY + ); + + if(xActiveSink.is()) + xActiveSink->setInputStream(result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::TIMEDOUT: + { + Reference<XInteractionRetry> xRet; + if(xInteract.is()) { + InteractiveNetworkConnectException aExcep; + INetURLObject aURL( + xContId.is() ? + xContId->getContentIdentifier() : + rtl::OUString() ); + aExcep.Server = aURL.GetHost(); + aExcep.Classification = InteractionClassification_ERROR; + aExcep.Message = + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "server not responding after five seconds")); + Any request; + request <<= aExcep; + ucbhelper::InteractionRequest *ir = + new ucbhelper::InteractionRequest(request); + Reference<XInteractionRequest> xIR(ir); + Sequence<Reference<XInteractionContinuation> > aSeq(2); + ucbhelper::InteractionRetry *retryP = + new ucbhelper::InteractionRetry(ir); + aSeq[0] = retryP; + ucbhelper::InteractionAbort *abortP = + new ucbhelper::InteractionAbort(ir); + aSeq[1] = abortP; + + ir->setContinuations(aSeq); + xInteract->handle(xIR); + rtl::Reference< ucbhelper::InteractionContinuation > ref + = ir->getSelection(); + if(ref.is()) { + Reference<XInterface> xInt(ref.get()); + xRet = Reference<XInteractionRetry>(xInt,UNO_QUERY); + } + } + + if(!xRet.is()) { + bAborted = true; + xLockBytes->SetError(ERRCODE_ABORT); + } + + break; + } + case Moderator::INTERACTIONREQUEST: + { + Reference<XInteractionRequest> Request; + res.result >>= Request; + xInteract->handle(Request); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::RESULT: + { + bResultAchieved = true; + aResult = res.result; + break; + } + case Moderator::COMMANDABORTED: + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + break; + } + case Moderator::COMMANDFAILED: + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + break; + } + case Moderator::INTERACTIVEIO: + { + bException = true; + if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED || + res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION ) + xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED ); + else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING ) + xLockBytes->SetError( ERRCODE_IO_NOTEXISTS ); + else if ( res.ioErrorCode == IOErrorCode_CANT_READ ) + xLockBytes->SetError( ERRCODE_IO_CANTREAD ); + else + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + break; + } + case Moderator::UNSUPPORTED: + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED ); + break; + } + default: + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + break; + } + } + + bResultAchieved |= bException; + bResultAchieved |= bAborted; + if(nTimeout == 5000) nTimeout *= 2; + } + + if(pMod) pMod->setReply(Moderator::EXIT); + + if ( bAborted || bException ) + { + if( xHandler.Is() ) + xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes ); + + Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY ); + if ( xActiveSink.is() ) + xActiveSink->setInputStream( Reference < XInputStream >() ); + + Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY ); + if ( xStreamer.is() ) + xStreamer->setStream( Reference < XStream >() ); + } + + Reference < XActiveDataControl > xControl( xSink, UNO_QUERY ); + if ( xControl.is() ) + xControl->terminate(); + + if ( xProps.is() ) + xProps->removePropertiesChangeListener( + Sequence< ::rtl::OUString >(), + xListener ); + + return ( bAborted || bException ); +} + +/** + Function for opening UCB contents synchronously + */ +static sal_Bool _UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ) +{ + ::ucbhelper::Content aContent( xContent, new UcbTaskEnvironment( xInteract, xProgress ) ); + Reference < XContentIdentifier > xIdent = xContent->getIdentifier(); + ::rtl::OUString aScheme = xIdent->getContentProviderScheme(); + + // http protocol must be handled in a special way: during the opening process the input stream may change + // only the last inputstream after notifying the document headers is valid + if ( aScheme.compareToAscii("http") != COMPARE_EQUAL ) + xLockBytes->SetStreamValid_Impl(); + + Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes ); + Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY ); + if ( xProps.is() ) + xProps->addPropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener ); + + Any aResult; + bool bException = false; + bool bAborted = false; + + try + { + aResult = aContent.executeCommand( rArg.Name, rArg.Argument ); + } + catch ( CommandAbortedException ) + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + } + catch ( CommandFailedException ) + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + } + catch ( InteractiveIOException& r ) + { + bException = true; + if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION ) + xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED ); + else if ( r.Code == IOErrorCode_NOT_EXISTING ) + xLockBytes->SetError( ERRCODE_IO_NOTEXISTS ); + else if ( r.Code == IOErrorCode_CANT_READ ) + xLockBytes->SetError( ERRCODE_IO_CANTREAD ); + else + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + catch ( UnsupportedDataSinkException& ) + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED ); + } + catch ( Exception ) + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + if ( bAborted || bException ) + { + if( xHandler.Is() ) + xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes ); + + Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY ); + if ( xActiveSink.is() ) + xActiveSink->setInputStream( Reference < XInputStream >() ); + + Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY ); + if ( xStreamer.is() ) + xStreamer->setStream( Reference < XStream >() ); + } + + Reference < XActiveDataControl > xControl( xSink, UNO_QUERY ); + if ( xControl.is() ) + xControl->terminate(); + + + if ( xProps.is() ) + xProps->removePropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener ); + + return ( bAborted || bException ); +} + + +//---------------------------------------------------------------------------- +UcbLockBytes::UcbLockBytes( UcbLockBytesHandler* pHandler ) + : m_xInputStream (NULL) + , m_pCommandThread( NULL ) + , m_xHandler( pHandler ) + , m_nError( ERRCODE_NONE ) + , m_bTerminated (sal_False) + , m_bDontClose( sal_False ) + , m_bStreamValid (sal_False) +{ + SetSynchronMode( TRUE ); +} + +//---------------------------------------------------------------------------- +UcbLockBytes::~UcbLockBytes() +{ + if ( !m_bDontClose ) + { + if ( m_xInputStream.is() ) + { + try + { + m_xInputStream->closeInput(); + } + catch ( RuntimeException const & ) + {} + catch ( IOException const & ) + {} + } + } + + if ( !m_xInputStream.is() && m_xOutputStream.is() ) + { + try + { + m_xOutputStream->closeOutput(); + } + catch ( RuntimeException const & ) + {} + catch ( IOException const & ) + {} + } +} + +Reference < XInputStream > UcbLockBytes::getInputStream() +{ + vos::OClearableGuard aGuard( m_aMutex ); + m_bDontClose = sal_True; + return m_xInputStream; +} + +Reference < XStream > UcbLockBytes::getStream() +{ + vos::OClearableGuard aGuard( m_aMutex ); + Reference < XStream > xStream( m_xSeekable, UNO_QUERY ); + if ( xStream.is() ) + m_bDontClose = sal_True; + return xStream; +} + +//---------------------------------------------------------------------------- + +sal_Bool UcbLockBytes::setStream_Impl( const Reference<XStream>& aStream ) +{ + vos::OClearableGuard aGuard( m_aMutex ); + if ( aStream.is() ) + { + m_xOutputStream = aStream->getOutputStream(); + setInputStream_Impl( aStream->getInputStream(), sal_False ); + m_xSeekable = Reference < XSeekable > ( aStream, UNO_QUERY ); + } + else + { + m_xOutputStream = Reference < XOutputStream >(); + setInputStream_Impl( Reference < XInputStream >() ); + } + + return m_xInputStream.is(); +} + +sal_Bool UcbLockBytes::setInputStream_Impl( const Reference<XInputStream> &rxInputStream, sal_Bool bSetXSeekable ) +{ + sal_Bool bRet = sal_False; + + try + { + vos::OClearableGuard aGuard( m_aMutex ); + + if ( !m_bDontClose && m_xInputStream.is() ) + m_xInputStream->closeInput(); + + m_xInputStream = rxInputStream; + + if( bSetXSeekable ) + { + m_xSeekable = Reference < XSeekable > ( rxInputStream, UNO_QUERY ); + if( !m_xSeekable.is() && rxInputStream.is() ) + { + Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + Reference< XOutputStream > rxTempOut = Reference < XOutputStream > ( + xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + UNO_QUERY ); + + if( rxTempOut.is() ) + { + ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut ); + m_xInputStream = Reference< XInputStream >( rxTempOut, UNO_QUERY ); + m_xSeekable = Reference < XSeekable > ( rxTempOut, UNO_QUERY ); + } + } + } + + bRet = m_xInputStream.is(); + // aGuard.clear(); + } + catch( Exception& ) + {} + + if ( m_bStreamValid && m_xInputStream.is() ) + m_aInitialized.set(); + + return bRet; +} + +void UcbLockBytes::SetStreamValid_Impl() +{ + m_bStreamValid = sal_True; + if ( m_xInputStream.is() ) + m_aInitialized.set(); +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::terminate_Impl() +{ + m_bTerminated = sal_True; + m_aInitialized.set(); + m_aTerminated.set(); + + if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() ) + { + DBG_ERROR("No InputStream, but no error set!" ); + SetError( ERRCODE_IO_NOTEXISTS ); + } + + if ( m_xHandler.Is() ) + m_xHandler->Handle( UcbLockBytesHandler::DONE, this ); +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::SetSynchronMode (BOOL bSynchron) +{ + SvLockBytes::SetSynchronMode (bSynchron); +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::ReadAt ( ULONG nPos, void *pBuffer, ULONG nCount, ULONG *pRead) const +{ + if ( IsSynchronMode() ) + { + UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this ); + pThis->m_aInitialized.wait(); + } + + Reference <XInputStream> xStream = getInputStream_Impl(); + if ( !xStream.is() ) + { + if ( m_bTerminated ) + return ERRCODE_IO_CANTREAD; + else + return ERRCODE_IO_PENDING; + } + + if ( pRead ) + *pRead = 0; + + Reference <XSeekable> xSeekable = getSeekable_Impl(); + if ( !xSeekable.is() ) + return ERRCODE_IO_CANTREAD; + + try + { + xSeekable->seek( nPos ); + } + catch ( IOException ) + { + return ERRCODE_IO_CANTSEEK; + } + catch (com::sun::star::lang::IllegalArgumentException) + { + return ERRCODE_IO_CANTSEEK; + } + + Sequence<sal_Int8> aData; + sal_Int32 nSize; + + nCount = VOS_MIN(nCount, 0x7FFFFFFF); + try + { + if ( !m_bTerminated && !IsSynchronMode() ) + { + sal_uInt64 nLen = xSeekable->getLength(); + if ( nPos + nCount > nLen ) + return ERRCODE_IO_PENDING; + } + + nSize = xStream->readBytes( aData, sal_Int32(nCount) ); + } + catch (IOException) + { + return ERRCODE_IO_CANTREAD; + } + + rtl_copyMemory (pBuffer, aData.getConstArray(), nSize); + if (pRead) + *pRead = ULONG(nSize); + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::WriteAt ( ULONG nPos, const void *pBuffer, ULONG nCount, ULONG *pWritten) +{ + if ( pWritten ) + *pWritten = 0; + + DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" ); + DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" ); + + Reference <XSeekable> xSeekable = getSeekable_Impl(); + Reference <XOutputStream> xOutputStream = getOutputStream_Impl(); + if ( !xOutputStream.is() || !xSeekable.is() ) + return ERRCODE_IO_CANTWRITE; + + try + { + xSeekable->seek( nPos ); + } + catch ( IOException ) + { + return ERRCODE_IO_CANTSEEK; + } + + sal_Int8* pData = (sal_Int8*) pBuffer; + Sequence<sal_Int8> aData( pData, nCount ); + try + { + xOutputStream->writeBytes( aData ); + if ( pWritten ) + *pWritten = nCount; + } + catch ( Exception ) + { + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::Flush() const +{ + Reference <XOutputStream > xOutputStream = getOutputStream_Impl(); + if ( !xOutputStream.is() ) + return ERRCODE_IO_CANTWRITE; + xOutputStream->flush(); + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::SetSize (ULONG nNewSize) +{ + SvLockBytesStat aStat; + Stat( &aStat, (SvLockBytesStatFlag) 0 ); + ULONG nSize = aStat.nSize; + + if ( nSize > nNewSize ) + { + Reference < XTruncate > xTrunc( getOutputStream_Impl(), UNO_QUERY ); + if ( xTrunc.is() ) + { + xTrunc->truncate(); + nSize = 0; + } + else { + DBG_WARNING("Not truncatable!"); + } + } + + if ( nSize < nNewSize ) + { + ULONG nDiff = nNewSize-nSize, nCount=0; + BYTE* pBuffer = new BYTE[ nDiff ]; + memset(pBuffer, 0, nDiff); // initialize for enhanced security + WriteAt( nSize, pBuffer, nDiff, &nCount ); + delete[] pBuffer; + if ( nCount != nDiff ) + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat, SvLockBytesStatFlag) const +{ + if ( IsSynchronMode() ) + { + UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this ); + pThis->m_aInitialized.wait(); + } + + if (!pStat) + return ERRCODE_IO_INVALIDPARAMETER; + + Reference <XInputStream> xStream = getInputStream_Impl(); + Reference <XSeekable> xSeekable = getSeekable_Impl(); + + if ( !xStream.is() ) + { + if ( m_bTerminated ) + return ERRCODE_IO_INVALIDACCESS; + else + return ERRCODE_IO_PENDING; + } + else if( !xSeekable.is() ) + return ERRCODE_IO_CANTTELL; + + try + { + pStat->nSize = ULONG(xSeekable->getLength()); + } + catch (IOException) + { + return ERRCODE_IO_CANTTELL; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::Cancel() +{ + // is alive only for compatibility reasons + OSL_ENSURE( m_bTerminated, "UcbLockBytes is not thread safe so it can be used only syncronously!\n" ); +} + +//---------------------------------------------------------------------------- +IMPL_LINK( UcbLockBytes, DataAvailHdl, void*, EMPTYARG ) +{ + if ( hasInputStream_Impl() && m_xHandler.Is() ) + m_xHandler->Handle( UcbLockBytesHandler::DATA_AVAILABLE, this ); + + return 0; +} + +UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream ) +{ + if( !xInputStream.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes(); + xLockBytes->setDontClose_Impl(); + xLockBytes->setInputStream_Impl( xInputStream ); + xLockBytes->terminate_Impl(); + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream ) +{ + if( !xStream.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes(); + xLockBytes->setDontClose_Impl(); + xLockBytes->setStream_Impl( xStream ); + xLockBytes->terminate_Impl(); + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const ::rtl::OUString& rReferer, const ::rtl::OUString& rMediaType, + const Reference < XInputStream >& xPostData, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler ) +{ + if( !xContent.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler ); + xLockBytes->SetSynchronMode( !pHandler ); + Reference< XActiveDataControl > xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes ); + + PostCommandArgument2 aArgument; + aArgument.Source = xPostData; + aArgument.Sink = xSink; + aArgument.MediaType = rMediaType; + aArgument.Referer = rReferer; + + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii ("post"); + aCommand.Argument <<= aArgument; + + Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) ); + + sal_Bool bError = UCBOpenContentSync( xLockBytes, + xContent, + aCommand, + xSink, + xInteractionHandler, + xProgressHdl, + pHandler ); + + if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) ) + { + DBG_ERROR("No InputStream, but no error set!" ); + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps, + StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler ) +{ + if( !xContent.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler ); + xLockBytes->SetSynchronMode( !pHandler ); + Reference< XActiveDataControl > xSink; + if ( eOpenMode & STREAM_WRITE ) + xSink = (XActiveDataControl*) new UcbStreamer_Impl( xLockBytes ); + else + xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes ); + + if ( rProps.getLength() ) + { + Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY ); + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii("setPropertyValues"); + aCommand.Handle = -1; /* unknown */ + aCommand.Argument <<= rProps; + xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() ); + } + + OpenCommandArgument2 aArgument; + aArgument.Sink = xSink; + aArgument.Mode = OpenMode::DOCUMENT; + + Command aCommand; + aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("open") ); + aCommand.Argument <<= aArgument; + + Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) ); + + sal_Bool bError = UCBOpenContentSync( xLockBytes, + xContent, + aCommand, + xSink, + xInteractionHandler, + xProgressHdl, + pHandler ); + + if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) ) + { + DBG_ERROR("No InputStream, but no error set!" ); + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + return xLockBytes; +} + +} diff --git a/unotools/source/ucbhelper/ucbstreamhelper.cxx b/unotools/source/ucbhelper/ucbstreamhelper.cxx new file mode 100644 index 000000000000..8a574dec66d4 --- /dev/null +++ b/unotools/source/ucbhelper/ucbstreamhelper.cxx @@ -0,0 +1,251 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ucbstreamhelper.cxx,v $ + * $Revision: 1.21 $ + * + * 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_unotools.hxx" + +#include <unotools/ucblockbytes.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/ucb/CommandAbortedException.hpp> + +#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HDL_ +#include <com/sun/star/ucb/XCommandEnvironment.hdl> +#endif +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/io/XActiveDataStreamer.hpp> + +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/content.hxx> +#include <tools/debug.hxx> +#include <unotools/streamwrap.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +namespace utl +{ + +static SvStream* lcl_CreateStream( const String& rFileName, StreamMode eOpenMode, + Reference < XInteractionHandler > xInteractionHandler, + UcbLockBytesHandler* pHandler, sal_Bool /*bForceSynchron*/, sal_Bool bEnsureFileExists ) +{ + SvStream* pStream = NULL; + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( pBroker ) + { + UcbLockBytesRef xLockBytes; + if ( eOpenMode & STREAM_WRITE ) + { + sal_Bool bTruncate = ( eOpenMode & STREAM_TRUNC ) != 0; + if ( bTruncate ) + { + try + { + // truncate is implemented with deleting the original file + ::ucbhelper::Content aCnt( rFileName, Reference < XCommandEnvironment >() ); + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) ); + } + + catch ( CommandAbortedException& ) + { + // couldn't truncate/delete + } + catch ( ContentCreationException& ) + { + } + catch ( Exception& ) + { + } + } + + if ( bEnsureFileExists || bTruncate ) + { + try + { + // make sure that the desired file exists before trying to open + SvMemoryStream aStream(0,0); + ::utl::OInputStreamWrapper* pInput = new ::utl::OInputStreamWrapper( aStream ); + Reference< XInputStream > xInput( pInput ); + + ::ucbhelper::Content aContent( rFileName, Reference < XCommandEnvironment >() ); + InsertCommandArgument aInsertArg; + aInsertArg.Data = xInput; + + aInsertArg.ReplaceExisting = sal_False; + Any aCmdArg; + aCmdArg <<= aInsertArg; + aContent.executeCommand( ::rtl::OUString::createFromAscii( "insert" ), aCmdArg ); + } + + // it is NOT an error when the stream already exists and no truncation was desired + catch ( CommandAbortedException& ) + { + // currently never an error is detected ! + } + catch ( ContentCreationException& ) + { + } + catch ( Exception& ) + { + } + } + } + + try + { + // create LockBytes using UCB + ::ucbhelper::Content aContent( rFileName, Reference < XCommandEnvironment >() ); + xLockBytes = UcbLockBytes::CreateLockBytes( aContent.get(), Sequence < PropertyValue >(), + eOpenMode, xInteractionHandler, pHandler ); + if ( xLockBytes.Is() ) + { + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + } + catch ( CommandAbortedException& ) + { + } + catch ( ContentCreationException& ) + { + } + catch ( Exception& ) + { + } + } + else + // if no UCB is present at least conventional file io is supported + pStream = new SvFileStream( rFileName, eOpenMode ); + + return pStream; +} + +//============================================================================ + +SvStream* UcbStreamHelper::CreateStream( const String& rFileName, StreamMode eOpenMode, + UcbLockBytesHandler* pHandler, sal_Bool bForceSynchron ) +{ + return lcl_CreateStream( rFileName, eOpenMode, Reference < XInteractionHandler >(), pHandler, bForceSynchron, sal_True /* bEnsureFileExists */ ); +} + +SvStream* UcbStreamHelper::CreateStream( const String& rFileName, StreamMode eOpenMode, + Reference < XInteractionHandler > xInteractionHandler, + UcbLockBytesHandler* pHandler, sal_Bool bForceSynchron ) +{ + return lcl_CreateStream( rFileName, eOpenMode, xInteractionHandler, pHandler, bForceSynchron, sal_True /* bEnsureFileExists */ ); +} + +SvStream* UcbStreamHelper::CreateStream( const String& rFileName, StreamMode eOpenMode, + sal_Bool bFileExists, + UcbLockBytesHandler* pHandler, sal_Bool bForceSynchron ) +{ + return lcl_CreateStream( rFileName, eOpenMode, Reference < XInteractionHandler >(), pHandler, bForceSynchron, !bFileExists ); +} + +SvStream* UcbStreamHelper::CreateStream( Reference < XInputStream > xStream ) +{ + SvStream* pStream = NULL; + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateInputLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + + return pStream; +} + +SvStream* UcbStreamHelper::CreateStream( Reference < XStream > xStream ) +{ + SvStream* pStream = NULL; + if ( xStream->getOutputStream().is() ) + { + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + } + else + return CreateStream( xStream->getInputStream() ); + + return pStream; +} + +SvStream* UcbStreamHelper::CreateStream( Reference < XInputStream > xStream, sal_Bool bCloseStream ) +{ + SvStream* pStream = NULL; + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateInputLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + if ( !bCloseStream ) + xLockBytes->setDontClose_Impl(); + + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + + return pStream; +}; + +SvStream* UcbStreamHelper::CreateStream( Reference < XStream > xStream, sal_Bool bCloseStream ) +{ + SvStream* pStream = NULL; + if ( xStream->getOutputStream().is() ) + { + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + if ( !bCloseStream ) + xLockBytes->setDontClose_Impl(); + + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + } + else + return CreateStream( xStream->getInputStream(), bCloseStream ); + + return pStream; +}; + +} diff --git a/unotools/source/ucbhelper/xtempfile.cxx b/unotools/source/ucbhelper/xtempfile.cxx new file mode 100644 index 000000000000..75024c3c9b35 --- /dev/null +++ b/unotools/source/ucbhelper/xtempfile.cxx @@ -0,0 +1,579 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xtempfile.cxx,v $ + * $Revision: 1.16 $ + * + * 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. + * + ************************************************************************/ +#include "precompiled_unotools.hxx" +#include <XTempFile.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/typeprovider.hxx> +#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP +#include <com/sun/star/registry/XRegistryKey.hpp> +#endif +#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP +#include <com/sun/star/beans/PropertyAttribute.hpp> +#endif +#include <unotools/tempfile.hxx> +#include <osl/file.hxx> +#include <unotools/configmgr.hxx> +#include <tools/urlobj.hxx> +#include <tools/debug.hxx> + +namespace css = com::sun::star; + +// copy define from desktop\source\app\appinit.cxx + +#define DESKTOP_TEMPNAMEBASE_DIR "/temp/soffice.tmp" + +OTempFileService::OTempFileService(::css::uno::Reference< ::css::uno::XComponentContext > const & context) +: ::cppu::PropertySetMixin< ::css::io::XTempFile >( + context + , static_cast< Implements >( IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET | IMPLEMENTS_PROPERTY_ACCESS ) + , com::sun::star::uno::Sequence< rtl::OUString >() ) +, mpStream( NULL ) +, mbRemoveFile( sal_True ) +, mbInClosed( sal_False ) +, mbOutClosed( sal_False ) +, mnCachedPos( 0 ) +, mbHasCachedPos( sal_False ) + +{ + mpTempFile = new ::utl::TempFile; + mpTempFile->EnableKillingFile ( sal_True ); +} + +OTempFileService::~OTempFileService () +{ + if ( mpTempFile ) + delete mpTempFile; +} + + +// XInterface + +::css::uno::Any SAL_CALL OTempFileService::queryInterface( ::css::uno::Type const & aType ) +throw ( ::css::uno::RuntimeException ) +{ + ::css::uno::Any aResult( OTempFileBase::queryInterface( aType ) ); + if (!aResult.hasValue()) + aResult = cppu::PropertySetMixin< ::css::io::XTempFile >::queryInterface( aType ) ; + return aResult; +}; +void SAL_CALL OTempFileService::acquire( ) +throw () +{ + OTempFileBase::acquire(); +} +void SAL_CALL OTempFileService::release( ) +throw () +{ + OTempFileBase::release(); +} + +// XTypeProvider + +::css::uno::Sequence< ::css::uno::Type > SAL_CALL OTempFileService::getTypes( ) +throw ( ::css::uno::RuntimeException ) +{ + static ::cppu::OTypeCollection* pTypeCollection = NULL; + if ( pTypeCollection == NULL ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ; + + if ( pTypeCollection == NULL ) + { + static ::cppu::OTypeCollection aTypeCollection( + ::getCppuType( ( const ::css::uno::Reference< ::css::beans::XPropertySet >*)NULL ) + ,OTempFileBase::getTypes() ); + pTypeCollection = &aTypeCollection; + } + } + return pTypeCollection->getTypes(); +}; +::css::uno::Sequence< sal_Int8 > SAL_CALL OTempFileService::getImplementationId( ) +throw ( ::css::uno::RuntimeException ) +{ + return OTempFileBase::getImplementationId(); +} + +// XTempFile + +sal_Bool SAL_CALL OTempFileService::getRemoveFile() +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + // the stream is already disconnected + throw ::css::uno::RuntimeException(); + } + + return mbRemoveFile; +}; +void SAL_CALL OTempFileService::setRemoveFile( sal_Bool _removefile ) +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + // the stream is already disconnected + throw ::css::uno::RuntimeException(); + } + + mbRemoveFile = _removefile; + mpTempFile->EnableKillingFile( mbRemoveFile ); +}; +::rtl::OUString SAL_CALL OTempFileService::getUri() +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + throw ::css::uno::RuntimeException(); + } + + return ::rtl::OUString( mpTempFile->GetURL() ); + +}; +::rtl::OUString SAL_CALL OTempFileService::getResourceName() +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + throw ::css::uno::RuntimeException(); +} + + return ::rtl::OUString( mpTempFile->GetFileName() ); +}; + + + +// XInputStream + +sal_Int32 SAL_CALL OTempFileService::readBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) +throw (::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + if (nBytesToRead < 0) + throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this)); + + aData.realloc(nBytesToRead); + + sal_uInt32 nRead = mpStream->Read(static_cast < void* > ( aData.getArray() ), nBytesToRead); + checkError(); + + if (nRead < static_cast < sal_uInt32 > ( nBytesToRead ) ) + aData.realloc( nRead ); + + if ( sal::static_int_cast<sal_uInt32>(nBytesToRead) > nRead ) + { + // usually that means that the stream was read till the end + // TODO/LATER: it is better to get rid of this optimization by avoiding using of multiple temporary files ( there should be only one temporary file? ) + mnCachedPos = mpStream->Tell(); + mbHasCachedPos = sal_True; + + mpStream = NULL; + if ( mpTempFile ) + mpTempFile->CloseStream(); + } + + return nRead; +} +sal_Int32 SAL_CALL OTempFileService::readSomeBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + checkError(); + + if (nMaxBytesToRead < 0) + throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast < ::css::uno::XWeak * >( this ) ); + + if (mpStream->IsEof()) + { + aData.realloc(0); + return 0; + } + else + return readBytes(aData, nMaxBytesToRead); +} +void SAL_CALL OTempFileService::skipBytes( sal_Int32 nBytesToSkip ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + checkError(); + mpStream->SeekRel(nBytesToSkip); + checkError(); +} +sal_Int32 SAL_CALL OTempFileService::available( ) +throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + + sal_uInt32 nPos = mpStream->Tell(); + checkError(); + + mpStream->Seek(STREAM_SEEK_TO_END); + checkError(); + + sal_Int32 nAvailable = (sal_Int32)mpStream->Tell() - nPos; + mpStream->Seek(nPos); + checkError(); + + return nAvailable; +} +void SAL_CALL OTempFileService::closeInput( ) +throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + mbInClosed = sal_True; + + if ( mbOutClosed ) + { + // stream will be deleted by TempFile implementation + mpStream = NULL; + + if ( mpTempFile ) + { + delete mpTempFile; + mpTempFile = NULL; + } + } +} + +// XOutputStream + +void SAL_CALL OTempFileService::writeBytes( const ::css::uno::Sequence< sal_Int8 >& aData ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbOutClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + sal_uInt32 nWritten = mpStream->Write(aData.getConstArray(),aData.getLength()); + checkError(); + if ( nWritten != (sal_uInt32)aData.getLength()) + throw ::css::io::BufferSizeExceededException( ::rtl::OUString(),static_cast < ::css::uno::XWeak * > ( this ) ); +} +void SAL_CALL OTempFileService::flush( ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbOutClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + mpStream->Flush(); + checkError(); +} +void SAL_CALL OTempFileService::closeOutput( ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbOutClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + mbOutClosed = sal_True; + + // TODO/LATER: it is better to get rid of this optimization by avoiding using of multiple temporary files ( there should be only one temporary file? ) + if ( mpStream ) + { + mnCachedPos = mpStream->Tell(); + mbHasCachedPos = sal_True; + + mpStream = NULL; + if ( mpTempFile ) + mpTempFile->CloseStream(); + } + + if ( mbInClosed ) + { + // stream will be deleted by TempFile implementation + mpStream = NULL; + + if ( mpTempFile ) + { + delete mpTempFile; + mpTempFile = NULL; + } + } +} + + +void OTempFileService::checkError () const +{ + if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); +} +void OTempFileService::checkConnected () +{ + if (!mpStream && mpTempFile) + { + mpStream = mpTempFile->GetStream( STREAM_STD_READWRITE ); + if ( mpStream && mbHasCachedPos ) + { + mpStream->Seek( sal::static_int_cast<sal_Size>(mnCachedPos) ); + if ( mpStream->SvStream::GetError () == ERRCODE_NONE ) + { + mbHasCachedPos = sal_False; + mnCachedPos = 0; + } + else + { + mpStream = NULL; + mpTempFile->CloseStream(); + } + } + } + + if (!mpStream) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); +} + +// XSeekable + +void SAL_CALL OTempFileService::seek( sal_Int64 nLocation ) +throw ( ::css::lang::IllegalArgumentException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + if ( nLocation < 0 || nLocation > getLength() ) + throw ::css::lang::IllegalArgumentException(); + + mpStream->Seek((sal_uInt32) nLocation ); + checkError(); +} +sal_Int64 SAL_CALL OTempFileService::getPosition( ) +throw ( ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + + sal_uInt32 nPos = mpStream->Tell(); + checkError(); + return (sal_Int64)nPos; +} +sal_Int64 SAL_CALL OTempFileService::getLength( ) +throw ( ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + + sal_uInt32 nCurrentPos = mpStream->Tell(); + checkError(); + + mpStream->Seek(STREAM_SEEK_TO_END); + sal_uInt32 nEndPos = mpStream->Tell(); + mpStream->Seek(nCurrentPos); + + checkError(); + + return (sal_Int64)nEndPos; +} + + +// XStream + +::css::uno::Reference< ::css::io::XInputStream > SAL_CALL OTempFileService::getInputStream() +throw ( ::css::uno::RuntimeException ) + { + return ::css::uno::Reference< ::css::io::XInputStream >( *this, ::css::uno::UNO_QUERY ); +} + +::css::uno::Reference< ::css::io::XOutputStream > SAL_CALL OTempFileService::getOutputStream() +throw ( ::css::uno::RuntimeException ) + { + return ::css::uno::Reference< ::css::io::XOutputStream >( *this, ::css::uno::UNO_QUERY ); + } + +// XTruncate + +void SAL_CALL OTempFileService::truncate() +throw ( ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + // SetStreamSize() call does not change the position + mpStream->Seek( 0 ); + mpStream->SetStreamSize( 0 ); + checkError(); +} + +// XServiceInfo + +::rtl::OUString SAL_CALL OTempFileService::getImplementationName() +throw ( ::css::uno::RuntimeException ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL OTempFileService::supportsService( ::rtl::OUString const & rServiceName ) +throw ( ::css::uno::RuntimeException ) +{ + ::css::uno::Sequence< ::rtl::OUString > aServices(getSupportedServiceNames_Static()); + return rServiceName == aServices[0]; +} + +::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames() +throw ( ::css::uno::RuntimeException ) +{ + return getSupportedServiceNames_Static(); +} + + + +::rtl::OUString OTempFileService::getImplementationName_Static () +{ + return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) ); +} +::css::uno::Sequence < ::rtl::OUString > OTempFileService::getSupportedServiceNames_Static() +{ + ::css::uno::Sequence < ::rtl::OUString > aNames ( 1 ); + aNames[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); + return aNames; +} +::css::uno::Reference < ::css::uno::XInterface >SAL_CALL XTempFile_createInstance( + css::uno::Reference< ::css::uno::XComponentContext > const & context) + SAL_THROW( ( css::uno::Exception ) ) +{ + return static_cast< ::cppu::OWeakObject * >( new OTempFileService(context) ); +} + +::css::uno::Reference < ::css::lang::XSingleComponentFactory > OTempFileService::createServiceFactory_Static( ::css::uno::Reference < ::css::lang::XMultiServiceFactory > const & ) +{ + return ::cppu::createSingleComponentFactory( XTempFile_createInstance, getImplementationName_Static(), getSupportedServiceNames_Static() ); +} + +static sal_Bool writeInfo( void * pRegistryKey, + const ::rtl::OUString & rImplementationName, + ::css::uno::Sequence< ::rtl::OUString > const & rServiceNames ) +{ + ::rtl::OUString aKeyName( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + aKeyName += rImplementationName; + aKeyName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "/UNO/SERVICES" ) ); + + ::css::uno::Reference< ::css::registry::XRegistryKey > xKey; + try + { + xKey = static_cast< ::css::registry::XRegistryKey * >( + pRegistryKey )->createKey( aKeyName ); + } + catch ( ::css::registry::InvalidRegistryException const & ) + { + } + + if ( !xKey.is() ) + return sal_False; + + sal_Bool bSuccess = sal_True; + + for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n ) + { + try + { + xKey->createKey( rServiceNames[ n ] ); + } + catch ( ::css::registry::InvalidRegistryException const & ) + { + bSuccess = sal_False; + break; + } + } + return bSuccess; +} +// C functions to implement this as a component + +extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +/** + * This function creates an implementation section in the registry and another subkey + * for each supported service. + * @param pServiceManager generic uno interface providing a service manager + * @param pRegistryKey generic uno interface providing registry key to write + */ +extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo( void* /*pServiceManager*/, void* pRegistryKey ) +{ + return pRegistryKey && + writeInfo (pRegistryKey, + OTempFileService::getImplementationName_Static(), + OTempFileService::getSupportedServiceNames_Static() ); +} + + +/** + * This function is called to get service factories for an implementation. + * @param pImplName name of implementation + * @param pServiceManager generic uno interface providing a service manager to instantiate components + * @param pRegistryKey registry data key to read and write component persistent data + * @return a component factory (generic uno interface) + */ +extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = 0; + ::css::uno::Reference< ::css::lang::XMultiServiceFactory > xSMgr( + reinterpret_cast< ::css::lang::XMultiServiceFactory * >( pServiceManager ) ); + ::css::uno::Reference< ::css::lang::XSingleComponentFactory > xFactory; + + if (OTempFileService::getImplementationName_Static().compareToAscii( pImplName ) == 0) + xFactory = OTempFileService::createServiceFactory_Static ( xSMgr ); + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} |