[Libreoffice] inelegancy in XStorage / path handling ...

Michael Meeks michael.meeks at novell.com
Fri Aug 26 09:45:11 PDT 2011


So,

	One of the things I was rather missing with our UNO storage interfaces
was the ability to resolve paths: [ would be quite a nice feature -
right ? ]. Unfortunately, since we have a mess of different UNO
interfaces to use for file-system (and storage) access, and few of them
overlap, from:

	* URLs - to XSimpleFileAccess
	* ucb's monstrous interfaces
	* XStorage / XStream / ...

	It seemed there was no way to do this - is that so ? anyhow, I wrote
some vaguely clean path resolution code that could be shared, in some
nice shared place. Of course, since interfaces are so beautifully
abstract - there is no way to associate these to with the underlying
interfaces usefully - they can't be added to the interface without
crippling each implementor: what we really need is some magic way to
associate implementations with interfaces (what an idea!) but anyhow -
perhaps someone else might just find comphelper's storagehelper if they
want this, urgh.

	Anyhow - package/'s ZipPackage.cxx does some hierarchical naming
lookups to validate the manifest - but does that via XTunnel and is
specific to its own implementation. Anyway, I got this written and
then ...

	Amazing - package/store/xstor/ocompinstream.cxx stream -magically-
invalidates itself if we don't keep a reference around to the parent
storage: a compelling feature if ever I saw one.

	At which point - I had to add this grotesque LifecycleProxy hack
(appended). If I was -really- 'clever' I could have - you know - done an
adaptive proxy object that would pretend to be whatever it is pointing
at, and hold the list of parents in there. [ Unfortunately, for all its
meta-power, UNO doesn't provide such an ability AFAICS - though it is
conceptually quite possible to have a 'TransparentProxy' object that
would do this ].

	Anyhow - distressed at having to do this; thoughts / indulgences
appreciated; since this is one of the cleaner hackarounds the Any("UNO")
"de-coupling" madness I'll push it.

	HTH,

		Michael.


diff --git a/comphelper/inc/comphelper/storagehelper.hxx b/comphelper/inc/comphelper/storagehelper.hxx
index 078bfb8..f4f0f81 100644
--- a/comphelper/inc/comphelper/storagehelper.hxx
+++ b/comphelper/inc/comphelper/storagehelper.hxx
@@ -167,6 +167,26 @@ public:
     static sal_Bool IsValidZipEntryFileName( const sal_Unicode *pChar, sal_Int32 nLength, sal_Bool bSlashAllowed );
 
     static sal_Bool PathHasSegment( const ::rtl::OUString& aPath, const ::rtl::OUString& aSegment );
+
+    // Methods to allow easy use of hierachical names inside storages
+
+    // Unfortunately - the impl.s of XStorage like to invalidate all
+    // their sub streams and storages when you release references, so
+    // it is necessary to keep references to all storages down the
+    // path - this is 'beautiful' (TM). So we need this ugly hack:
+    class LifecycleProxyImpl;
+    class LifecycleProxy {
+    public:
+        LifecycleProxyImpl *pBadness;
+        LifecycleProxy();
+        ~LifecycleProxy();
+    };
+    static ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > GetStorageAtPath(
+        const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > &xStorage,
+        const ::rtl::OUString& aPath, sal_uInt32 nOpenMode, LifecycleProxy &rNastiness );
+    static ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > GetStreamAtPath(
+        const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage > &xStorage,
+        const ::rtl::OUString& aPath, sal_uInt32 nOpenMode, LifecycleProxy &rNastiness );
 };
 
 }
diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx
index 70b7852..52b8e67 100644
--- a/comphelper/source/misc/storagehelper.cxx
+++ b/comphelper/source/misc/storagehelper.cxx
@@ -39,6 +39,7 @@
 #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp>
 #include <com/sun/star/xml/crypto/DigestID.hpp>
 
+#include <vector>
 #include <rtl/digest.h>
 
 #include <ucbhelper/content.hxx>
@@ -536,6 +537,58 @@ sal_Bool OStorageHelper::PathHasSegment( const ::rtl::OUString& aPath, const ::r
     return bResult;
 }
 
+class OStorageHelper::LifecycleProxyImpl : public std::vector< uno::Reference< embed::XStorage > > {};
+OStorageHelper::LifecycleProxy::LifecycleProxy() :
+        pBadness( new OStorageHelper::LifecycleProxyImpl() ) { }
+OStorageHelper::LifecycleProxy::~LifecycleProxy() { delete pBadness; }
+
+static void splitPath( std::vector<rtl::OUString> &rElems,
+                       const ::rtl::OUString& rPath )
+{
+    for (sal_Int32 i = 0; i >= 0;)
+        rElems.push_back( rPath.getToken( 0, '/', i ) );
+}
+
+static uno::Reference< embed::XStorage > LookupStorageAtPath(
+        const uno::Reference< embed::XStorage > &xParentStorage,
+        std::vector<rtl::OUString> &rElems, sal_uInt32 nOpenMode,
+        OStorageHelper::LifecycleProxy &rNastiness )
+{
+    uno::Reference< embed::XStorage > xStorage( xParentStorage );
+    rNastiness.pBadness->push_back( xStorage );
+    for( size_t i = 0; i < rElems.size() && xStorage.is(); i++ )
+    {
+        xStorage = xStorage->openStorageElement( rElems[i], nOpenMode );
+        rNastiness.pBadness->push_back( xStorage );
+    }
+    return xStorage;
+}
+
+uno::Reference< embed::XStorage > OStorageHelper::GetStorageAtPath(
+        const uno::Reference< embed::XStorage > &xStorage,
+        const ::rtl::OUString& rPath, sal_uInt32 nOpenMode,
+        OStorageHelper::LifecycleProxy &rNastiness )
+{
+    std::vector<rtl::OUString> aElems;
+    splitPath( aElems, rPath );
+    return LookupStorageAtPath( xStorage, aElems, nOpenMode, rNastiness );
+}
+
+uno::Reference< io::XStream > OStorageHelper::GetStreamAtPath(
+        const uno::Reference< embed::XStorage > &xParentStorage,
+        const ::rtl::OUString& rPath, sal_uInt32 nOpenMode,
+        OStorageHelper::LifecycleProxy &rNastiness )
+{
+    std::vector<rtl::OUString> aElems;
+    splitPath( aElems, rPath );
+    rtl::OUString aName( aElems.back() );
+    aElems.pop_back();
+    uno::Reference< embed::XStorage > xStorage(
+        LookupStorageAtPath( xParentStorage, aElems, nOpenMode, rNastiness ),
+        uno::UNO_QUERY_THROW );
+    return xStorage->openStreamElement( aName, nOpenMode );
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

-- 
 michael.meeks at novell.com  <><, Pseudo Engineer, itinerant idiot





More information about the LibreOffice mailing list