26#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
27#include <com/sun/star/embed/ElementModes.hpp>
28#include <com/sun/star/io/TextInputStream.hpp>
29#include <com/sun/star/util/XModifiable.hpp>
32#include <rtl/ustrbuf.hxx>
39 using css::uno::Reference;
40 using css::uno::UNO_QUERY;
41 using css::uno::UNO_QUERY_THROW;
42 using css::uno::UNO_SET_THROW;
43 using css::uno::Exception;
44 using css::uno::Sequence;
45 using css::uno::XComponentContext;
46 using css::embed::XStorage;
47 using css::frame::XController;
48 using css::sdb::application::XDatabaseDocumentUI;
49 using css::lang::XComponent;
50 using css::io::XStream;
51 using css::io::TextInputStream;
52 using css::io::XTextInputStream2;
53 using css::util::XModifiable;
55 namespace ElementModes = css::embed::ElementModes;
60 void lcl_getPersistentRepresentation(
const MapStringToCompDesc::value_type& i_rComponentDesc, OUStringBuffer& o_rBuffer )
62 o_rBuffer.append( i_rComponentDesc.first );
63 o_rBuffer.append(
'=' );
64 o_rBuffer.append( i_rComponentDesc.second.sName );
65 o_rBuffer.append(
',' );
66 o_rBuffer.append(
sal_Unicode( i_rComponentDesc.second.bForEditing ?
'1' :
'0' ) );
69 bool lcl_extractCompDesc( std::u16string_view i_rIniLine, OUString& o_rStorName, SubComponentDescriptor& o_rCompDesc )
71 const size_t nEqualSignPos = i_rIniLine.find(
'=' );
72 if ( nEqualSignPos == 0 || nEqualSignPos == std::u16string_view::npos )
74 OSL_FAIL(
"lcl_extractCompDesc: invalid map file entry - unexpected pos of '='" );
77 o_rStorName = i_rIniLine.substr( 0, nEqualSignPos );
79 const size_t nCommaPos = i_rIniLine.rfind(
',' );
80 if ( nCommaPos != i_rIniLine.size() - 2 )
82 OSL_FAIL(
"lcl_extractCompDesc: invalid map file entry - unexpected pos of ','" );
85 o_rCompDesc.sName = i_rIniLine.substr( nEqualSignPos + 1, nCommaPos - nEqualSignPos - 1 );
86 o_rCompDesc.bForEditing = ( i_rIniLine[ nCommaPos + 1 ] ==
'1' );
90 constexpr OUStringLiteral sRecoveryDataSubStorageName =
u"recovery";
92 constexpr OUStringLiteral sObjectMapStreamName =
u"storage-component-map.ini";
94 void lcl_writeObjectMap_throw(
const Reference<XComponentContext> & i_rContext,
const Reference< XStorage >& i_rStorage,
97 if ( i_mapStorageToCompDesc.empty() )
101 StorageTextOutputStream aTextOutput( i_rContext, i_rStorage, sObjectMapStreamName );
103 aTextOutput.writeLine(
"[storages]" );
105 for (
auto const& elem : i_mapStorageToCompDesc)
107 OUStringBuffer aLine;
108 lcl_getPersistentRepresentation(elem, aLine);
110 aTextOutput.writeLine( aLine.makeStringAndClear() );
113 aTextOutput.writeLine();
116 bool lcl_isSectionStart( std::u16string_view i_rIniLine, OUString& o_rSectionName )
118 const size_t nLen = i_rIniLine.size();
121 o_rSectionName = i_rIniLine.substr( 1, nLen -2 );
127 void lcl_stripTrailingLineFeed( OUString& io_rLine )
129 const sal_Int32 nLen = io_rLine.getLength();
130 if ( io_rLine.endsWith(
"\n") )
131 io_rLine = io_rLine.copy( 0, nLen - 1 );
134 void lcl_readObjectMap_throw(
const Reference<XComponentContext> & i_rxContext,
const Reference< XStorage >& i_rStorage,
138 if ( !i_rStorage->hasByName( sObjectMapStreamName ) )
140 OSL_FAIL(
"lcl_readObjectMap_throw: if there's no map file, then there's expected to be no storage, too!" );
144 Reference< XStream > xIniStream( i_rStorage->openStreamElement(
145 sObjectMapStreamName, ElementModes::READ ), UNO_SET_THROW );
147 Reference< XTextInputStream2 > xTextInput = TextInputStream::create( i_rxContext );
148 xTextInput->setEncoding(
"UTF-8" );
149 xTextInput->setInputStream( xIniStream->getInputStream() );
151 OUString sCurrentSection;
152 bool bCurrentSectionIsKnownToBeUnsupported =
true;
153 while ( !xTextInput->isEOF() )
155 OUString sLine = xTextInput->readLine();
156 lcl_stripTrailingLineFeed( sLine );
158 if ( sLine.isEmpty() )
161 if ( lcl_isSectionStart( sLine, sCurrentSection ) )
163 bCurrentSectionIsKnownToBeUnsupported =
false;
167 if ( bCurrentSectionIsKnownToBeUnsupported )
171 if ( sCurrentSection !=
"storages" )
173 bCurrentSectionIsKnownToBeUnsupported =
true;
177 OUString sStorageName;
178 SubComponentDescriptor aCompDesc;
179 if ( !lcl_extractCompDesc( sLine, sStorageName, aCompDesc ) )
181 o_mapStorageToObjectName[ sStorageName ] = aCompDesc;
185 void lcl_markModified(
const Reference< XComponent >& i_rSubComponent )
187 const Reference< XModifiable > xModify( i_rSubComponent, UNO_QUERY );
190 OSL_FAIL(
"lcl_markModified: unhandled case!" );
194 xModify->setModified(
true );
209 const std::vector< Reference< XController > >& i_rControllers )
214 if ( i_rTargetStorage->hasByName( sRecoveryDataSubStorageName ) )
215 i_rTargetStorage->removeElement( sRecoveryDataSubStorageName );
216 Reference< XStorage > xRecoveryStorage = i_rTargetStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READWRITE );
219 if ( !i_rControllers.empty() )
221 ENSURE_OR_THROW( i_rControllers.size() == 1,
"can't handle more than one controller" );
229 for (
auto const& controller : i_rControllers)
231 Reference< XDatabaseDocumentUI > xDatabaseUI(controller, UNO_QUERY_THROW);
232 const Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
234 for (
auto const & component : aComponents )
241 for (
auto const& elem : aMapCompDescs)
243 Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
245 lcl_writeObjectMap_throw(
mxContext, xComponentsStor, elem.second );
255 const Reference< XController >& i_rTargetController )
257 ENSURE_OR_THROW( i_rDocumentStorage.is(),
"illegal document storage" );
258 Reference< XDatabaseDocumentUI > xDocumentUI( i_rTargetController, UNO_QUERY_THROW );
260 if ( !i_rDocumentStorage->hasByName( sRecoveryDataSubStorageName ) )
265 Reference< XStorage > xRecoveryStorage = i_rDocumentStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READ );
275 Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
277 lcl_readObjectMap_throw(
mxContext, xComponentsStor, aMapCompDescs[ aKnownType ] );
278 xComponentsStor->dispose();
282 for (
auto const& elemMapCompDescs : aMapCompDescs)
287 Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
291 for (
auto const& elem : elemMapCompDescs.second)
293 const OUString sComponentName(elem.second.sName);
294 if ( !xComponentsStor->hasByName(elem.first) )
297 "DatabaseDocumentRecovery::recoverSubDocuments: inconsistent recovery storage: storage '" <<
299 "' not found in '" <<
301 "', but required per map file!" );
306 if ( !xDocumentUI->isConnected() )
307 xDocumentUI->connect();
310 Reference< XStorage > xCompStor( xComponentsStor->openStorageElement( elem.first, ElementModes::READ ) );
312 Reference< XComponent > xSubComponent( aComponentRecovery.
recoverFromStorage( xCompStor, sComponentName, elem.second.bForEditing ) );
316 lcl_markModified( xSubComponent );
319 xComponentsStor->dispose();
322 xRecoveryStorage->dispose();
327 i_rDocumentStorage->removeElement( sRecoveryDataSubStorageName );
void recoverSubDocuments(const css::uno::Reference< css::embed::XStorage > &i_rDocumentStorage, const css::uno::Reference< css::frame::XController > &i_rTargetController)
recovery sub components from the given document storage, if applicable
DatabaseDocumentRecovery(const css::uno::Reference< css::uno::XComponentContext > &i_rContext)
void saveModifiedSubComponents(const css::uno::Reference< css::embed::XStorage > &i_rTargetStorage, const std::vector< css::uno::Reference< css::frame::XController > > &i_rControllers)
saves the modified sub components of the given controller(s) to the "recovery" sub storage of the doc...
~DatabaseDocumentRecovery()
css::uno::Reference< css::uno::XComponentContext > mxContext
css::uno::Reference< css::lang::XComponent > recoverFromStorage(const css::uno::Reference< css::embed::XStorage > &i_rRecoveryStorage, const OUString &i_rComponentName, const bool i_bForEditing)
static OUString getComponentsStorageName(const SubComponentType i_eType)
void saveToRecoveryStorage(const css::uno::Reference< css::embed::XStorage > &i_rRecoveryStorage, MapCompTypeToCompDescs &io_mapCompDescs)
#define ENSURE_OR_THROW(c, m)
#define DBG_UNHANDLED_EXCEPTION(...)
#define SAL_WARN(area, stream)
std::unordered_map< OUString, SubComponentDescriptor > MapStringToCompDesc
std::map< SubComponentType, MapStringToCompDesc > MapCompTypeToCompDescs
constexpr bool ends_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept