1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <oox/helper/storagebase.hxx>
21 
22 #include <com/sun/star/embed/XTransactedObject.hpp>
23 #include <com/sun/star/io/XStream.hpp>
24 #include <osl/diagnose.h>
25 #include <rtl/ustrbuf.hxx>
26 #include <oox/helper/binaryinputstream.hxx>
27 #include <oox/helper/binaryoutputstream.hxx>
28 
29 namespace oox {
30 
31 using namespace ::com::sun::star::embed;
32 using namespace ::com::sun::star::io;
33 using namespace ::com::sun::star::uno;
34 
35 namespace {
36 
lclSplitFirstElement(OUString & orElement,OUString & orRemainder,const OUString & _aFullName)37 void lclSplitFirstElement( OUString& orElement, OUString& orRemainder, const OUString& _aFullName )
38 {
39     OUString aFullName = _aFullName;
40     sal_Int32  nSlashPos = aFullName.indexOf( '/' );
41 
42     // strip leading slashes
43     while( nSlashPos == 0 )
44     {
45         aFullName = aFullName.copy(1);
46         nSlashPos = aFullName.indexOf( '/' );
47     }
48 
49     if( (0 <= nSlashPos) && (nSlashPos < aFullName.getLength()) )
50     {
51         orElement = aFullName.copy( 0, nSlashPos );
52         orRemainder = aFullName.copy( nSlashPos + 1 );
53     }
54     else
55     {
56         orElement = aFullName;
57     }
58 }
59 
60 } // namespace
61 
StorageBase(const Reference<XInputStream> & rxInStream,bool bBaseStreamAccess)62 StorageBase::StorageBase( const Reference< XInputStream >& rxInStream, bool bBaseStreamAccess ) :
63     mxInStream( rxInStream ),
64     mbBaseStreamAccess( bBaseStreamAccess ),
65     mbReadOnly( true )
66 {
67     OSL_ENSURE( mxInStream.is(), "StorageBase::StorageBase - missing base input stream" );
68 }
69 
StorageBase(const Reference<XStream> & rxOutStream,bool bBaseStreamAccess)70 StorageBase::StorageBase( const Reference< XStream >& rxOutStream, bool bBaseStreamAccess ) :
71     mxOutStream( rxOutStream ),
72     mbBaseStreamAccess( bBaseStreamAccess ),
73     mbReadOnly( false )
74 {
75     OSL_ENSURE( mxOutStream.is(), "StorageBase::StorageBase - missing base output stream" );
76 }
77 
StorageBase(const StorageBase & rParentStorage,const OUString & rStorageName,bool bReadOnly)78 StorageBase::StorageBase( const StorageBase& rParentStorage, const OUString& rStorageName, bool bReadOnly ) :
79     maParentPath( rParentStorage.getPath() ),
80     maStorageName( rStorageName ),
81     mbBaseStreamAccess( false ),
82     mbReadOnly( bReadOnly )
83 {
84 }
85 
~StorageBase()86 StorageBase::~StorageBase()
87 {
88 }
89 
isStorage() const90 bool StorageBase::isStorage() const
91 {
92     return implIsStorage();
93 }
94 
isRootStorage() const95 bool StorageBase::isRootStorage() const
96 {
97     return implIsStorage() && maStorageName.isEmpty();
98 }
99 
getXStorage() const100 Reference< XStorage > StorageBase::getXStorage() const
101 {
102     return implGetXStorage();
103 }
104 
getPath() const105 OUString StorageBase::getPath() const
106 {
107     OUStringBuffer aBuffer( maParentPath );
108     if( !aBuffer.isEmpty() )
109         aBuffer.append( '/' );
110     aBuffer.append( maStorageName );
111     return aBuffer.makeStringAndClear();
112 }
113 
getElementNames(::std::vector<OUString> & orElementNames) const114 void StorageBase::getElementNames( ::std::vector< OUString >& orElementNames ) const
115 {
116     orElementNames.clear();
117     implGetElementNames( orElementNames );
118 }
119 
openSubStorage(const OUString & rStorageName,bool bCreateMissing)120 StorageRef StorageBase::openSubStorage( const OUString& rStorageName, bool bCreateMissing )
121 {
122     StorageRef xSubStorage;
123     OSL_ENSURE( !bCreateMissing || !mbReadOnly, "StorageBase::openSubStorage - cannot create substorage in read-only mode" );
124     if( !bCreateMissing || !mbReadOnly )
125     {
126         OUString aElement, aRemainder;
127         lclSplitFirstElement( aElement, aRemainder, rStorageName );
128         if( !aElement.isEmpty() )
129             xSubStorage = getSubStorage( aElement, bCreateMissing );
130         if( xSubStorage.get() && !aRemainder.isEmpty() )
131             xSubStorage = xSubStorage->openSubStorage( aRemainder, bCreateMissing );
132     }
133     return xSubStorage;
134 }
135 
openInputStream(const OUString & rStreamName)136 Reference< XInputStream > StorageBase::openInputStream( const OUString& rStreamName )
137 {
138     Reference< XInputStream > xInStream;
139     OUString aElement, aRemainder;
140     lclSplitFirstElement( aElement, aRemainder, rStreamName );
141     if( !aElement.isEmpty() )
142     {
143         if( !aRemainder.isEmpty() )
144         {
145             StorageRef xSubStorage = getSubStorage( aElement, false );
146             if( xSubStorage.get() )
147                 xInStream = xSubStorage->openInputStream( aRemainder );
148         }
149         else
150         {
151             xInStream = implOpenInputStream( aElement );
152         }
153     }
154     else if( mbBaseStreamAccess )
155     {
156         xInStream = mxInStream;
157     }
158     return xInStream;
159 }
160 
openOutputStream(const OUString & rStreamName)161 Reference< XOutputStream > StorageBase::openOutputStream( const OUString& rStreamName )
162 {
163     Reference< XOutputStream > xOutStream;
164     OSL_ENSURE( !mbReadOnly, "StorageBase::openOutputStream - cannot create output stream in read-only mode" );
165     if( !mbReadOnly )
166     {
167         OUString aElement, aRemainder;
168         lclSplitFirstElement( aElement, aRemainder, rStreamName );
169         if( !aElement.isEmpty() )
170         {
171             if( !aRemainder.isEmpty() )
172             {
173                 StorageRef xSubStorage = getSubStorage( aElement, true );
174                 if( xSubStorage.get() )
175                     xOutStream = xSubStorage->openOutputStream( aRemainder );
176             }
177             else
178             {
179                 xOutStream = implOpenOutputStream( aElement );
180             }
181         }
182         else if( mbBaseStreamAccess )
183         {
184             xOutStream = mxOutStream->getOutputStream();
185         }
186     }
187     return xOutStream;
188 }
189 
copyToStorage(StorageBase & rDestStrg,const OUString & rElementName)190 void StorageBase::copyToStorage( StorageBase& rDestStrg, const OUString& rElementName )
191 {
192     OSL_ENSURE( rDestStrg.isStorage() && !rDestStrg.isReadOnly(), "StorageBase::copyToStorage - invalid destination" );
193     OSL_ENSURE( !rElementName.isEmpty(), "StorageBase::copyToStorage - invalid element name" );
194     if( rDestStrg.isStorage() && !rDestStrg.isReadOnly() && !rElementName.isEmpty() )
195     {
196         StorageRef xSubStrg = openSubStorage( rElementName, false );
197         if( xSubStrg.get() )
198         {
199             StorageRef xDestSubStrg = rDestStrg.openSubStorage( rElementName, true );
200             if( xDestSubStrg.get() )
201                 xSubStrg->copyStorageToStorage( *xDestSubStrg );
202         }
203         else
204         {
205             Reference< XInputStream > xInStrm = openInputStream( rElementName );
206             if( xInStrm.is() )
207             {
208                 Reference< XOutputStream > xOutStrm = rDestStrg.openOutputStream( rElementName );
209                 if( xOutStrm.is() )
210                 {
211                     BinaryXInputStream aInStrm( xInStrm, true );
212                     BinaryXOutputStream aOutStrm( xOutStrm, true );
213                     aInStrm.copyToStream( aOutStrm );
214                 }
215             }
216         }
217     }
218 }
219 
copyStorageToStorage(StorageBase & rDestStrg)220 void StorageBase::copyStorageToStorage( StorageBase& rDestStrg )
221 {
222     OSL_ENSURE( rDestStrg.isStorage() && !rDestStrg.isReadOnly(), "StorageBase::copyToStorage - invalid destination" );
223     if( rDestStrg.isStorage() && !rDestStrg.isReadOnly() )
224     {
225         ::std::vector< OUString > aElements;
226         getElementNames( aElements );
227         for (auto const& elem : aElements)
228             copyToStorage(rDestStrg, elem);
229     }
230 }
231 
commit()232 void StorageBase::commit()
233 {
234     OSL_ENSURE( !mbReadOnly, "StorageBase::commit - cannot commit in read-only mode" );
235     if( !mbReadOnly )
236     {
237         // commit all open substorages
238         maSubStorages.forEachMem( &StorageBase::commit );
239         // commit this storage
240         implCommit();
241     }
242 }
243 
244 // private --------------------------------------------------------------------
245 
getSubStorage(const OUString & rElementName,bool bCreateMissing)246 StorageRef StorageBase::getSubStorage( const OUString& rElementName, bool bCreateMissing )
247 {
248     StorageRef& rxSubStrg = maSubStorages[ rElementName ];
249     if( !rxSubStrg )
250         rxSubStrg = implOpenSubStorage( rElementName, bCreateMissing );
251     return rxSubStrg;
252 }
253 
254 } // namespace oox
255 
256 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
257