Add a comment to clarify what kind of inputs the class handles
[LibreOffice.git] / sw / source / filter / writer / writer.cxx
blob0576663965c9edc001fc271e4d89d1dfb63293fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <memory>
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>
30 #include <doc.hxx>
31 #include <docary.hxx>
32 #include <IMark.hxx>
33 #include <IDocumentSettingAccess.hxx>
34 #include <IDocumentMarkAccess.hxx>
35 #include <numrule.hxx>
36 #include <swerror.h>
37 #include <com/sun/star/ucb/ContentCreationException.hpp>
39 using namespace css;
41 typedef std::multimap<SwNodeOffset, const ::sw::mark::MarkBase*> SwBookmarkNodeTable;
43 struct Writer_Impl
45 SvStream * m_pStream;
47 std::map<OUString, OUString> maFileNameMap;
48 std::vector<SfxPoolItemHolder> aFontRemoveLst;
49 SwBookmarkNodeTable aBkmkNodePos;
51 Writer_Impl();
53 void RemoveFontList();
54 void InsertBkmk( const ::sw::mark::MarkBase& rBkmk );
57 Writer_Impl::Writer_Impl()
58 : m_pStream(nullptr)
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
82 * and is a DLL !
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
86 * output-functions.
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.
93 Writer::Writer()
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;
105 Writer::~Writer()
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);
122 if( m_pCurrentPam )
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;
130 m_pDoc = 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();
152 return true;
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();
163 return -1;
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);
179 pNew->SetMark();
180 aStt = nEndIdx;
181 pCNode = aStt.GetNode().GetContentNode();
182 if (!pCNode)
183 pCNode = SwNodes::GoPrevious(&aStt);
184 assert(pCNode && "No more ContentNode at StartPos");
185 pNew->GetPoint()->AssignEndIndex( *pCNode );
186 return pNew;
189 // Stream-specific
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 )
203 if ( IsStgWriter() )
205 ErrCodeMsg nResult = ERRCODE_ABORT;
208 rtl::Reference<SotStorage> aRef = new SotStorage(rStrm);
209 nResult = Write( rPaM, *aRef, pFName );
210 if ( nResult == ERRCODE_NONE )
211 aRef->Commit();
213 catch (const css::ucb::ContentCreationException &)
215 TOOLS_WARN_EXCEPTION("sw", "Writer::Write caught");
217 return nResult;
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
229 m_pOrigPam = &rPaM;
231 ErrCode nRet = WriteStream();
233 ResetWriter();
235 return nRet;
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
266 bool bRet = false;
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())))
277 return bRet;
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;
285 return true;
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() );
296 aSrcFile.Close();
297 aDstFile.Commit();
299 bRet = ERRCODE_NONE == aDstFile.GetErrorIgnoreWarning();
301 if( bRet )
303 m_pImpl->maFileNameMap.insert( std::make_pair( aSrc, aDest ) );
304 rFileNm = aDest;
307 return bRet;
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();
319 bool bCheck = false;
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();
332 if( !pFont )
333 pFont = *pDefFont;
335 if( bCheck )
337 if( *pFont == *pDefFont )
338 continue;
340 else if( *pFont == *pDefFont )
341 bCheck = true;
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 );
378 return true;
381 else
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)");
401 else
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();
417 ++ppBkmk)
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() )
436 // all
437 for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
438 rArr.push_back( it->second );
439 else
441 for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
443 const ::sw::mark::MarkBase& rBkmk = *(it->second);
444 sal_Int32 nContent;
445 if( rBkmk.GetMarkPos().GetNode() == rNd &&
446 (nContent = rBkmk.GetMarkPos().GetContentIndex() ) >= nStt &&
447 nContent < nEnd )
449 rArr.push_back( &rBkmk );
451 else if( rBkmk.IsExpanded() &&
452 (rNd == rBkmk.GetOtherMarkPos().GetNode()) &&
453 (nContent = rBkmk.GetOtherMarkPos().GetContentIndex()) >= nStt &&
454 nContent < nEnd )
456 rArr.push_back( &rBkmk );
461 return !rArr.empty();
464 // Storage-specific
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 )
473 SetStream(nullptr);
474 m_pStg = &rStg;
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
483 m_pOrigPam = &rPaM;
485 ErrCodeMsg nRet = WriteStorage();
487 m_pStg = nullptr;
488 ResetWriter();
490 return nRet;
493 ErrCodeMsg StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const OUString* pFName, SfxMedium* pMedium )
495 SetStream(nullptr);
496 m_pStg = nullptr;
497 m_xStg = rStg;
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
506 m_pOrigPam = &rPaM;
508 ErrCodeMsg nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
510 m_pStg = nullptr;
511 ResetWriter();
513 return nRet;
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */