1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <hintids.hxx>
23 #include <sot/storage.hxx>
24 #include <sfx2/docfile.hxx>
25 #include <comphelper/diagnose_ex.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/eeitem.hxx>
28 #include <osl/diagnose.h>
29 #include <shellio.hxx>
33 #include <IDocumentSettingAccess.hxx>
34 #include <IDocumentMarkAccess.hxx>
35 #include <numrule.hxx>
37 #include <com/sun/star/ucb/ContentCreationException.hpp>
41 typedef std::multimap
<SwNodeOffset
, const ::sw::mark::MarkBase
*> SwBookmarkNodeTable
;
47 std::map
<OUString
, OUString
> maFileNameMap
;
48 std::vector
<SfxPoolItemHolder
> aFontRemoveLst
;
49 SwBookmarkNodeTable aBkmkNodePos
;
53 void RemoveFontList();
54 void InsertBkmk( const ::sw::mark::MarkBase
& rBkmk
);
57 Writer_Impl::Writer_Impl()
62 void Writer_Impl::RemoveFontList()
64 aFontRemoveLst
.clear();
67 void Writer_Impl::InsertBkmk(const ::sw::mark::MarkBase
& rBkmk
)
69 SwNodeOffset nNd
= rBkmk
.GetMarkPos().GetNodeIndex();
71 aBkmkNodePos
.emplace( nNd
, &rBkmk
);
73 if(rBkmk
.IsExpanded() && rBkmk
.GetOtherMarkPos().GetNodeIndex() != nNd
)
75 nNd
= rBkmk
.GetOtherMarkPos().GetNodeIndex();
76 aBkmkNodePos
.emplace( nNd
, &rBkmk
);
81 * This module is the central collection point for all writer-filters
84 * So that the Writer can work with different writers, the output-functions
85 * of the content carrying objects have to be mapped to the various
88 * For that, to inquire its output function, every object can be gripped
89 * via the which-value in a table.
90 * These functions are available in the corresponding Writer-DLL's.
94 : m_pImpl(std::make_unique
<Writer_Impl
>())
95 , m_pOrigFileName(nullptr), m_pDoc(nullptr), m_pOrigPam(nullptr)
96 , m_bHideDeleteRedlines(false)
98 m_bWriteAll
= m_bShowProgress
= m_bUCS2_WithStartChar
= true;
99 m_bASCII_NoLastLineEnd
= m_bASCII_ParaAsBlank
= m_bASCII_ParaAsCR
=
100 m_bWriteClipboardDoc
= m_bWriteOnlyFirstTable
= m_bBlock
=
101 m_bOrganizerMode
= false;
102 m_bExportParagraphNumbering
= true;
110 * Document Interface Access
112 IDocumentSettingAccess
& Writer::getIDocumentSettingAccess() { return m_pDoc
->getIDocumentSettingAccess(); }
113 const IDocumentSettingAccess
& Writer::getIDocumentSettingAccess() const { return m_pDoc
->getIDocumentSettingAccess(); }
114 IDocumentStylePoolAccess
& Writer::getIDocumentStylePoolAccess() { return m_pDoc
->getIDocumentStylePoolAccess(); }
115 const IDocumentStylePoolAccess
& Writer::getIDocumentStylePoolAccess() const { return m_pDoc
->getIDocumentStylePoolAccess(); }
117 void Writer::ResetWriter()
119 m_pImpl
->RemoveFontList();
120 m_pImpl
.reset(new Writer_Impl
);
124 while (m_pCurrentPam
->GetNext() != m_pCurrentPam
.get())
125 delete m_pCurrentPam
->GetNext();
126 m_pCurrentPam
.reset();
128 m_pCurrentPam
= nullptr;
129 m_pOrigFileName
= nullptr;
132 m_bShowProgress
= m_bUCS2_WithStartChar
= true;
133 m_bASCII_NoLastLineEnd
= m_bASCII_ParaAsBlank
= m_bASCII_ParaAsCR
=
134 m_bWriteClipboardDoc
= m_bWriteOnlyFirstTable
= m_bBlock
=
135 m_bOrganizerMode
= false;
138 bool Writer::CopyNextPam( SwPaM
** ppPam
)
140 if( (*ppPam
)->GetNext() == m_pOrigPam
)
142 *ppPam
= m_pOrigPam
; // set back to the beginning pam
143 return false; // end of the ring
146 // otherwise copy the next value from the next Pam
147 *ppPam
= (*ppPam
)->GetNext();
149 *m_pCurrentPam
->GetPoint() = *(*ppPam
)->Start();
150 *m_pCurrentPam
->GetMark() = *(*ppPam
)->End();
155 // search the next Bookmark-Position from the Bookmark-Table
157 sal_Int32
Writer::FindPos_Bkmk(const SwPosition
& rPos
) const
159 const IDocumentMarkAccess
* const pMarkAccess
= m_pDoc
->getIDocumentMarkAccess();
160 const auto ppBkmk
= pMarkAccess
->findFirstBookmarkNotStartsBefore(rPos
);
161 if(ppBkmk
!= pMarkAccess
->getBookmarksEnd())
162 return ppBkmk
- pMarkAccess
->getBookmarksBegin();
166 std::shared_ptr
<SwUnoCursor
>
167 Writer::NewUnoCursor(SwDoc
& rDoc
, SwNodeOffset
const nStartIdx
, SwNodeOffset
const nEndIdx
)
169 SwNodes
*const pNds
= &rDoc
.GetNodes();
171 SwNodeIndex
aStt( *pNds
, nStartIdx
);
172 SwContentNode
* pCNode
= aStt
.GetNode().GetContentNode();
173 if (!pCNode
&& nullptr == SwNodes::GoNext(&aStt
))
175 OSL_FAIL( "No more ContentNode at StartPos" );
178 auto const pNew
= rDoc
.CreateUnoCursor(SwPosition(aStt
), false);
181 pCNode
= aStt
.GetNode().GetContentNode();
183 pCNode
= SwNodes::GoPrevious(&aStt
);
184 assert(pCNode
&& "No more ContentNode at StartPos");
185 pNew
->GetPoint()->AssignEndIndex( *pCNode
);
190 SvStream
& Writer::Strm()
192 assert(m_pImpl
->m_pStream
&& "Oh-oh. Writer with no Stream!");
193 return *m_pImpl
->m_pStream
;
196 void Writer::SetStream(SvStream
*const pStream
)
198 m_pImpl
->m_pStream
= pStream
;
201 ErrCodeMsg
Writer::Write( SwPaM
& rPaM
, SvStream
& rStrm
, const OUString
* pFName
)
205 ErrCodeMsg nResult
= ERRCODE_ABORT
;
208 rtl::Reference
<SotStorage
> aRef
= new SotStorage(rStrm
);
209 nResult
= Write( rPaM
, *aRef
, pFName
);
210 if ( nResult
== ERRCODE_NONE
)
213 catch (const css::ucb::ContentCreationException
&)
215 TOOLS_WARN_EXCEPTION("sw", "Writer::Write caught");
220 m_pDoc
= &rPaM
.GetDoc();
221 m_pOrigFileName
= pFName
;
222 m_pImpl
->m_pStream
= &rStrm
;
224 // Copy PaM, so that it can be modified
225 m_pCurrentPam
= m_pDoc
->CreateUnoCursor(*rPaM
.End(), false);
226 m_pCurrentPam
->SetMark();
227 *m_pCurrentPam
->GetPoint() = *rPaM
.Start();
228 // for comparison secure to the current Pam
231 ErrCode nRet
= WriteStream();
238 void Writer::SetupFilterOptions(SfxMedium
& /*rMedium*/)
241 ErrCodeMsg
Writer::Write( SwPaM
& rPam
, SfxMedium
& rMedium
, const OUString
* pFileName
)
243 SetupFilterOptions(rMedium
);
244 // This method must be overridden in SwXMLWriter a storage from medium will be used there.
245 // The microsoft format can write to storage but the storage will be based on the stream.
246 return Write( rPam
, *rMedium
.GetOutStream(), pFileName
);
249 ErrCodeMsg
Writer::Write( SwPaM
& /*rPam*/, SotStorage
&, const OUString
* )
251 OSL_ENSURE( false, "Write in Storages on a stream?" );
252 return ERR_SWG_WRITE_ERROR
;
255 ErrCodeMsg
Writer::Write( SwPaM
&, const uno::Reference
< embed::XStorage
>&, const OUString
*, SfxMedium
* )
257 OSL_ENSURE( false, "Write in Storages on a stream?" );
258 return ERR_SWG_WRITE_ERROR
;
261 bool Writer::CopyLocalFileToINet( OUString
& rFileNm
)
263 if( !m_pOrigFileName
) // can be happen, by example if we
264 return false; // write into the clipboard
267 INetURLObject
aFileUrl( rFileNm
), aTargetUrl( *m_pOrigFileName
);
269 if (!(INetProtocol::File
== aFileUrl
.GetProtocol()
270 && (INetProtocol::Http
== aTargetUrl
.GetProtocol()
271 || INetProtocol::Https
== aTargetUrl
.GetProtocol()
272 || INetProtocol::VndSunStarWebdav
== aTargetUrl
.GetProtocol()
273 || INetProtocol::Smb
== aTargetUrl
.GetProtocol()
274 || INetProtocol::Sftp
== aTargetUrl
.GetProtocol()
275 || INetProtocol::Cmis
== aTargetUrl
.GetProtocol())))
280 // has the file been moved?
281 std::map
<OUString
, OUString
>::iterator it
= m_pImpl
->maFileNameMap
.find( rFileNm
);
282 if ( it
!= m_pImpl
->maFileNameMap
.end() )
284 rFileNm
= it
->second
;
288 OUString aSrc
= rFileNm
;
289 OUString aDest
= aTargetUrl
.GetPartBeforeLastName() + aFileUrl
.GetLastName();
291 SfxMedium
aSrcFile( aSrc
, StreamMode::READ
);
292 SfxMedium
aDstFile( aDest
, StreamMode::WRITE
| StreamMode::SHARE_DENYNONE
);
294 aDstFile
.GetOutStream()->WriteStream( *aSrcFile
.GetInStream() );
299 bRet
= ERRCODE_NONE
== aDstFile
.GetErrorIgnoreWarning();
303 m_pImpl
->maFileNameMap
.insert( std::make_pair( aSrc
, aDest
) );
310 void Writer::PutNumFormatFontsInAttrPool()
312 // then there are a few fonts in the NumRules
313 // These put into the Pool. After this does they have a RefCount > 1
314 // it can be removed - it is already in the Pool
315 SfxItemPool
& rPool
= m_pDoc
->GetAttrPool();
316 const SwNumRuleTable
& rListTable
= m_pDoc
->GetNumRuleTable();
317 const SwNumFormat
* pFormat
;
318 const vcl::Font
* pDefFont
= &numfunc::GetDefBulletFont();
321 for( size_t nGet
= rListTable
.size(); nGet
; )
323 SwNumRule
const*const pRule
= rListTable
[ --nGet
];
324 if (m_pDoc
->IsUsed(*pRule
))
326 for( sal_uInt8 nLvl
= 0; nLvl
< MAXLEVEL
; ++nLvl
)
328 if( SVX_NUM_CHAR_SPECIAL
== (pFormat
= &pRule
->Get( nLvl
))->GetNumberingType() ||
329 SVX_NUM_BITMAP
== pFormat
->GetNumberingType() )
331 std::optional
<vcl::Font
> pFont
= pFormat
->GetBulletFont();
337 if( *pFont
== *pDefFont
)
340 else if( *pFont
== *pDefFont
)
343 AddFontItem( rPool
, SvxFontItem( pFont
->GetFamilyType(),
344 pFont
->GetFamilyName(), pFont
->GetStyleName(),
345 pFont
->GetPitch(), pFont
->GetCharSet(), RES_CHRATR_FONT
));
352 void Writer::PutEditEngFontsInAttrPool()
354 SfxItemPool
& rPool
= m_pDoc
->GetAttrPool();
355 if( rPool
.GetSecondaryPool() )
357 AddFontItems_( rPool
, EE_CHAR_FONTINFO
);
358 AddFontItems_( rPool
, EE_CHAR_FONTINFO_CJK
);
359 AddFontItems_( rPool
, EE_CHAR_FONTINFO_CTL
);
363 void Writer::AddFontItems_( SfxItemPool
& rPool
, TypedWhichId
<SvxFontItem
> nWhich
)
365 const SvxFontItem
* pFont
= &rPool
.GetUserOrPoolDefaultItem( nWhich
);
366 AddFontItem( rPool
, *pFont
);
368 pFont
= rPool
.GetUserDefaultItem( nWhich
);
369 if( nullptr != pFont
)
370 AddFontItem( rPool
, *pFont
);
372 if (nWhich
== RES_CHRATR_FONT
|| nWhich
== RES_CHRATR_CJK_FONT
|| nWhich
== RES_CHRATR_CTL_FONT
)
374 m_pDoc
->ForEachCharacterFontItem(nWhich
, /*bIgnoreAutoStyles*/false,
375 [this, &rPool
] (const SvxFontItem
& rFontItem
) -> bool
377 AddFontItem( rPool
, rFontItem
);
383 // nWhich is one of EE_CHAR_FONTINFO / EE_CHAR_FONTINFO_CJK / rPool, EE_CHAR_FONTINFO_CTL
384 ItemSurrogates aSurrogates
;
385 rPool
.GetItemSurrogates(aSurrogates
, nWhich
);
386 for (const SfxPoolItem
* pItem
: aSurrogates
)
387 AddFontItem( rPool
, *static_cast<const SvxFontItem
*>(pItem
) );
391 void Writer::AddFontItem( SfxItemPool
& rPool
, const SvxFontItem
& rFont
)
393 SfxPoolItemHolder aItem
;
394 if( RES_CHRATR_FONT
!= rFont
.Which() )
396 SvxFontItem
aFont( rFont
);
397 aFont
.SetWhich( RES_CHRATR_FONT
);
398 aItem
= SfxPoolItemHolder(rPool
, &aFont
);
399 assert(aItem
.getItem() != &aFont
&& "Pointer to local outside scope (pushed to aFontRemoveLst)");
402 aItem
= SfxPoolItemHolder(rPool
, &rFont
);
404 if(1 == aItem
.getItem()->GetRefCount())
406 m_pImpl
->aFontRemoveLst
.push_back(aItem
);
410 // build a bookmark table, which is sort by the node position. The
411 // OtherPos of the bookmarks also inserted.
412 void Writer::CreateBookmarkTable()
414 const IDocumentMarkAccess
* const pMarkAccess
= m_pDoc
->getIDocumentMarkAccess();
415 for(auto ppBkmk
= pMarkAccess
->getBookmarksBegin();
416 ppBkmk
!= pMarkAccess
->getBookmarksEnd();
419 m_pImpl
->InsertBkmk(**ppBkmk
);
423 // search all Bookmarks in the range and return it in the Array
424 bool Writer::GetBookmarks(const SwContentNode
& rNd
, sal_Int32 nStt
,
425 sal_Int32 nEnd
, std::vector
< const ::sw::mark::MarkBase
* >& rArr
)
427 OSL_ENSURE( rArr
.empty(), "there are still entries available" );
429 SwNodeOffset nNd
= rNd
.GetIndex();
430 std::pair
<SwBookmarkNodeTable::const_iterator
, SwBookmarkNodeTable::const_iterator
> aIterPair
431 = m_pImpl
->aBkmkNodePos
.equal_range( nNd
);
432 if( aIterPair
.first
!= aIterPair
.second
)
434 // there exist some bookmarks, search now all which is in the range
435 if( !nStt
&& nEnd
== rNd
.Len() )
437 for( SwBookmarkNodeTable::const_iterator it
= aIterPair
.first
; it
!= aIterPair
.second
; ++it
)
438 rArr
.push_back( it
->second
);
441 for( SwBookmarkNodeTable::const_iterator it
= aIterPair
.first
; it
!= aIterPair
.second
; ++it
)
443 const ::sw::mark::MarkBase
& rBkmk
= *(it
->second
);
445 if( rBkmk
.GetMarkPos().GetNode() == rNd
&&
446 (nContent
= rBkmk
.GetMarkPos().GetContentIndex() ) >= nStt
&&
449 rArr
.push_back( &rBkmk
);
451 else if( rBkmk
.IsExpanded() &&
452 (rNd
== rBkmk
.GetOtherMarkPos().GetNode()) &&
453 (nContent
= rBkmk
.GetOtherMarkPos().GetContentIndex()) >= nStt
&&
456 rArr
.push_back( &rBkmk
);
461 return !rArr
.empty();
465 ErrCode
StgWriter::WriteStream()
467 OSL_ENSURE( false, "Write in Storages on a stream?" );
468 return ERR_SWG_WRITE_ERROR
;
471 ErrCodeMsg
StgWriter::Write( SwPaM
& rPaM
, SotStorage
& rStg
, const OUString
* pFName
)
475 m_pDoc
= &rPaM
.GetDoc();
476 m_pOrigFileName
= pFName
;
478 // Copy PaM, so that it can be modified
479 m_pCurrentPam
= m_pDoc
->CreateUnoCursor(*rPaM
.End(), false);
480 m_pCurrentPam
->SetMark();
481 *m_pCurrentPam
->GetPoint() = *rPaM
.Start();
482 // for comparison secure to the current Pam
485 ErrCodeMsg nRet
= WriteStorage();
493 ErrCodeMsg
StgWriter::Write( SwPaM
& rPaM
, const uno::Reference
< embed::XStorage
>& rStg
, const OUString
* pFName
, SfxMedium
* pMedium
)
498 m_pDoc
= &rPaM
.GetDoc();
499 m_pOrigFileName
= pFName
;
501 // Copy PaM, so that it can be modified
502 m_pCurrentPam
= m_pDoc
->CreateUnoCursor(*rPaM
.End(), false);
503 m_pCurrentPam
->SetMark();
504 *m_pCurrentPam
->GetPoint() = *rPaM
.Start();
505 // for comparison secure to the current Pam
508 ErrCodeMsg nRet
= pMedium
? WriteMedium( *pMedium
) : WriteStorage();
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */