Line data Source code
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 <hintids.hxx>
21 :
22 : #include <sot/storage.hxx>
23 : #include <sfx2/docfile.hxx>
24 : #include <svl/urihelper.hxx>
25 : #include <vcl/graphicfilter.hxx>
26 : #include <editeng/fontitem.hxx>
27 : #include <editeng/eeitem.hxx>
28 : #include <o3tl/make_unique.hxx>
29 : #include <shellio.hxx>
30 : #include <doc.hxx>
31 : #include <docary.hxx>
32 : #include <IMark.hxx>
33 : #include <IDocumentSettingAccess.hxx>
34 : #include <numrule.hxx>
35 : #include <swerror.h>
36 :
37 : using namespace css;
38 :
39 : namespace
40 : {
41 12873 : SvStream& lcl_OutLongExt( SvStream& rStrm, sal_uLong nVal, bool bNeg )
42 : {
43 : sal_Char aBuf[28];
44 :
45 12873 : int i = SAL_N_ELEMENTS(aBuf);
46 12873 : aBuf[--i] = 0;
47 23672 : do
48 : {
49 23672 : aBuf[--i] = '0' + static_cast<sal_Char>(nVal % 10);
50 23672 : nVal /= 10;
51 : } while (nVal);
52 :
53 12873 : if (bNeg)
54 361 : aBuf[--i] = '-';
55 :
56 12873 : return rStrm.WriteCharPtr( &aBuf[i] );
57 : }
58 : }
59 :
60 : typedef std::multimap<sal_uLong, const ::sw::mark::IMark*> SwBookmarkNodeTable;
61 :
62 : struct Writer_Impl
63 : {
64 : SvStream * m_pStream;
65 :
66 : std::vector<const SvxFontItem*> aFontRemoveLst;
67 : SwBookmarkNodeTable aBkmkNodePos;
68 :
69 : Writer_Impl();
70 : ~Writer_Impl();
71 :
72 : void RemoveFontList( SwDoc& rDoc );
73 : void InsertBkmk( const ::sw::mark::IMark& rBkmk );
74 : };
75 :
76 16485 : Writer_Impl::Writer_Impl()
77 16485 : : m_pStream(0)
78 : {
79 16485 : }
80 :
81 16485 : Writer_Impl::~Writer_Impl()
82 : {
83 16485 : }
84 :
85 8195 : void Writer_Impl::RemoveFontList( SwDoc& rDoc )
86 : {
87 25200 : for( std::vector<const SvxFontItem*>::const_iterator it = aFontRemoveLst.begin();
88 16800 : it != aFontRemoveLst.end(); ++it )
89 : {
90 205 : rDoc.GetAttrPool().Remove( **it );
91 : }
92 8195 : }
93 :
94 9 : void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
95 : {
96 9 : sal_uLong nNd = rBkmk.GetMarkPos().nNode.GetIndex();
97 :
98 9 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ) );
99 :
100 9 : if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
101 : {
102 0 : nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
103 0 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ));
104 : }
105 9 : }
106 :
107 : /*
108 : * This module is the central collection point for all writer-filters
109 : * and is a DLL !
110 : *
111 : * So that the Writer can work with different writers, the output-functions
112 : * of the content carrying objects have to be mapped to the various
113 : * output-functions.
114 : *
115 : * For that, to inquire its output function, every object can be gripped
116 : * via the which-value in a table.
117 : * These functions are available in the corresponding Writer-DLL's.
118 : */
119 :
120 8290 : Writer::Writer()
121 : : m_pImpl(o3tl::make_unique<Writer_Impl>())
122 8290 : , pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
123 : {
124 8290 : bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
125 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
126 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
127 8290 : bOrganizerMode = false;
128 8290 : bExportPargraphNumbering = true;
129 8290 : }
130 :
131 8290 : Writer::~Writer()
132 : {
133 8290 : }
134 :
135 : /*
136 : * Document Interface Access
137 : */
138 32 : IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return &pDoc->getIDocumentSettingAccess(); }
139 0 : const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return &pDoc->getIDocumentSettingAccess(); }
140 28 : IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return &pDoc->getIDocumentStylePoolAccess(); }
141 0 : const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return &pDoc->getIDocumentStylePoolAccess(); }
142 :
143 8195 : void Writer::ResetWriter()
144 : {
145 8195 : m_pImpl->RemoveFontList( *pDoc );
146 8195 : m_pImpl.reset(new Writer_Impl);
147 :
148 8195 : if( pCurPam )
149 : {
150 16390 : while( pCurPam->GetNext() != pCurPam )
151 0 : delete pCurPam->GetNext();
152 8195 : delete pCurPam;
153 : }
154 8195 : pCurPam = 0;
155 8195 : pOrigFileName = 0;
156 8195 : pDoc = 0;
157 :
158 8195 : bShowProgress = bUCS2_WithStartChar = true;
159 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
160 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
161 8195 : bOrganizerMode = false;
162 8195 : }
163 :
164 8353 : bool Writer::CopyNextPam( SwPaM ** ppPam )
165 : {
166 8353 : if( (*ppPam)->GetNext() == pOrigPam )
167 : {
168 8353 : *ppPam = pOrigPam; // set back to the beginning pam
169 8353 : return false; // end of the ring
170 : }
171 :
172 : // otherwise copy the next value from the next Pam
173 0 : *ppPam = static_cast<SwPaM*>((*ppPam)->GetNext() );
174 :
175 0 : *pCurPam->GetPoint() = *(*ppPam)->Start();
176 0 : *pCurPam->GetMark() = *(*ppPam)->End();
177 :
178 0 : return true;
179 : }
180 :
181 : // search the next Bookmark-Position from the Bookmark-Table
182 :
183 541 : sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
184 : {
185 541 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
186 : const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
187 541 : pMarkAccess->getAllMarksBegin(),
188 541 : pMarkAccess->getAllMarksEnd(),
189 : rPos,
190 1082 : sw::mark::CompareIMarkStartsBefore()); // find the first Mark that does not start before
191 541 : if(ppBkmk != pMarkAccess->getAllMarksEnd())
192 1 : return ppBkmk - pMarkAccess->getAllMarksBegin();
193 540 : return -1;
194 : }
195 :
196 : SwPaM *
197 953 : Writer::NewSwPaM(SwDoc & rDoc, sal_uLong const nStartIdx, sal_uLong const nEndIdx)
198 : {
199 953 : SwNodes *const pNds = &rDoc.GetNodes();
200 :
201 953 : SwNodeIndex aStt( *pNds, nStartIdx );
202 953 : SwContentNode* pCNode = aStt.GetNode().GetContentNode();
203 953 : if( !pCNode && 0 == pNds->GoNext( &aStt ) )
204 : {
205 : OSL_FAIL( "No more ContentNode at StartPos" );
206 : }
207 :
208 953 : SwPaM* pNew = new SwPaM( aStt );
209 953 : pNew->SetMark();
210 953 : aStt = nEndIdx;
211 953 : pCNode = aStt.GetNode().GetContentNode();
212 953 : if (!pCNode)
213 953 : pCNode = SwNodes::GoPrevious(&aStt);
214 : assert(pCNode && "No more ContentNode at StartPos");
215 953 : pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
216 953 : pNew->GetPoint()->nNode = aStt;
217 953 : return pNew;
218 : }
219 :
220 : // Stream-specific
221 93155 : SvStream& Writer::Strm()
222 : {
223 : assert(m_pImpl->m_pStream && "Oh-oh. Writer with no Stream!");
224 93155 : return *m_pImpl->m_pStream;
225 : }
226 :
227 262 : void Writer::SetStream(SvStream *const pStream)
228 : {
229 262 : m_pImpl->m_pStream = pStream;
230 262 : }
231 :
232 1586 : SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
233 : {
234 1586 : const bool bNeg = nVal < 0;
235 1586 : if (bNeg)
236 361 : nVal = -nVal;
237 :
238 1586 : return lcl_OutLongExt(rStrm, static_cast<sal_uLong>(nVal), bNeg);
239 : }
240 :
241 11287 : SvStream& Writer::OutULong( SvStream& rStrm, sal_uLong nVal )
242 : {
243 11287 : return lcl_OutLongExt(rStrm, nVal, false);
244 : }
245 :
246 8124 : sal_uLong Writer::Write( SwPaM& rPaM, SvStream& rStrm, const OUString* pFName )
247 : {
248 8124 : if ( IsStgWriter() )
249 : {
250 32 : sal_uLong nResult = ERRCODE_ABORT;
251 : try
252 : {
253 32 : tools::SvRef<SotStorage> aRef = new SotStorage( rStrm );
254 32 : nResult = Write( rPaM, *aRef, pFName );
255 32 : if ( nResult == ERRCODE_NONE )
256 32 : aRef->Commit();
257 : }
258 0 : catch (const css::ucb::ContentCreationException &e)
259 : {
260 : SAL_WARN("sw", "Writer::Write caught " << e.Message);
261 : }
262 32 : return nResult;
263 : }
264 :
265 8092 : pDoc = rPaM.GetDoc();
266 8092 : pOrigFileName = pFName;
267 8092 : m_pImpl->m_pStream = &rStrm;
268 :
269 : // Copy PaM, so that it can be modified
270 8092 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
271 : // for comparison secure to the current Pam
272 8092 : pOrigPam = &rPaM;
273 :
274 8092 : sal_uLong nRet = WriteStream();
275 :
276 8092 : ResetWriter();
277 :
278 8092 : return nRet;
279 : }
280 :
281 33 : void Writer::SetupFilterOptions(SfxMedium& /*rMedium*/)
282 33 : {}
283 :
284 48 : sal_uLong Writer::Write( SwPaM& rPam, SfxMedium& rMedium, const OUString* pFileName )
285 : {
286 48 : SetupFilterOptions(rMedium);
287 : // This method must be overridden in SwXMLWriter a storage from medium will be used there.
288 : // The microsoft format can write to storage but the storage will be based on the stream.
289 48 : return Write( rPam, *rMedium.GetOutStream(), pFileName );
290 : }
291 :
292 0 : sal_uLong Writer::Write( SwPaM& /*rPam*/, SotStorage&, const OUString* )
293 : {
294 : OSL_ENSURE( false, "Write in Storages on a stream?" );
295 0 : return ERR_SWG_WRITE_ERROR;
296 : }
297 :
298 0 : sal_uLong Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const OUString*, SfxMedium* )
299 : {
300 : OSL_ENSURE( false, "Write in Storages on a stream?" );
301 0 : return ERR_SWG_WRITE_ERROR;
302 : }
303 :
304 71 : void Writer::PutNumFormatFontsInAttrPool()
305 : {
306 : // then there are a few fonts in the NumRules
307 : // These put into the Pool. After this does they have a RefCount > 1
308 : // it can be removed - it is already in the Pool
309 71 : SfxItemPool& rPool = pDoc->GetAttrPool();
310 71 : const SwNumRuleTable& rListTable = pDoc->GetNumRuleTable();
311 : const SwNumRule* pRule;
312 : const SwNumFormat* pFormat;
313 : const vcl::Font* pFont;
314 71 : const vcl::Font* pDefFont = &numfunc::GetDefBulletFont();
315 71 : bool bCheck = false;
316 :
317 280 : for( size_t nGet = rListTable.size(); nGet; )
318 138 : if( SwDoc::IsUsed( *(pRule = rListTable[ --nGet ] )))
319 143 : for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
320 226 : if( SVX_NUM_CHAR_SPECIAL == (pFormat = &pRule->Get( nLvl ))->GetNumberingType() ||
321 96 : SVX_NUM_BITMAP == pFormat->GetNumberingType() )
322 : {
323 34 : if( 0 == ( pFont = pFormat->GetBulletFont() ) )
324 10 : pFont = pDefFont;
325 :
326 34 : if( bCheck )
327 : {
328 9 : if( *pFont == *pDefFont )
329 9 : continue;
330 : }
331 25 : else if( *pFont == *pDefFont )
332 1 : bCheck = true;
333 :
334 : _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
335 25 : pFont->GetName(), pFont->GetStyleName(),
336 50 : pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
337 : }
338 71 : }
339 :
340 71 : void Writer::PutEditEngFontsInAttrPool( bool bIncl_CJK_CTL )
341 : {
342 71 : SfxItemPool& rPool = pDoc->GetAttrPool();
343 71 : if( rPool.GetSecondaryPool() )
344 : {
345 71 : _AddFontItems( rPool, EE_CHAR_FONTINFO );
346 71 : if( bIncl_CJK_CTL )
347 : {
348 71 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
349 71 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
350 : }
351 : }
352 71 : }
353 :
354 213 : void Writer::_AddFontItems( SfxItemPool& rPool, sal_uInt16 nW )
355 : {
356 213 : const SvxFontItem* pFont = static_cast<const SvxFontItem*>(&rPool.GetDefaultItem( nW ));
357 213 : _AddFontItem( rPool, *pFont );
358 :
359 213 : if( 0 != ( pFont = static_cast<const SvxFontItem*>(rPool.GetPoolDefaultItem( nW ))) )
360 213 : _AddFontItem( rPool, *pFont );
361 :
362 213 : sal_uInt32 nMaxItem = rPool.GetItemCount2( nW );
363 229 : for( sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet )
364 16 : if( 0 != (pFont = static_cast<const SvxFontItem*>(rPool.GetItem2( nW, nGet ))) )
365 16 : _AddFontItem( rPool, *pFont );
366 213 : }
367 :
368 467 : void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
369 : {
370 : const SvxFontItem* pItem;
371 467 : if( RES_CHRATR_FONT != rFont.Which() )
372 : {
373 442 : SvxFontItem aFont( rFont );
374 442 : aFont.SetWhich( RES_CHRATR_FONT );
375 442 : pItem = static_cast<const SvxFontItem*>(&rPool.Put( aFont ));
376 : }
377 : else
378 25 : pItem = static_cast<const SvxFontItem*>(&rPool.Put( rFont ));
379 :
380 467 : if( 1 < pItem->GetRefCount() )
381 262 : rPool.Remove( *pItem );
382 : else
383 : {
384 205 : m_pImpl->aFontRemoveLst.push_back( pItem );
385 : }
386 467 : }
387 :
388 : // build a bookmark table, which is sort by the node position. The
389 : // OtherPos of the bookmarks also inserted.
390 32 : void Writer::CreateBookmarkTable()
391 : {
392 32 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
393 123 : for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
394 82 : ppBkmk != pMarkAccess->getBookmarksEnd();
395 : ++ppBkmk)
396 : {
397 9 : m_pImpl->InsertBkmk(**ppBkmk);
398 : }
399 32 : }
400 :
401 : // search alle Bookmarks in the range and return it in the Array
402 1006 : bool Writer::GetBookmarks(const SwContentNode& rNd, sal_Int32 nStt,
403 : sal_Int32 nEnd, std::vector< const ::sw::mark::IMark* >& rArr)
404 : {
405 : OSL_ENSURE( rArr.empty(), "there are still entries available" );
406 :
407 1006 : sal_uLong nNd = rNd.GetIndex();
408 : std::pair<SwBookmarkNodeTable::const_iterator, SwBookmarkNodeTable::const_iterator> aIterPair
409 1006 : = m_pImpl->aBkmkNodePos.equal_range( nNd );
410 1006 : if( aIterPair.first != aIterPair.second )
411 : {
412 : // there exist some bookmarks, search now all which is in the range
413 53 : if( !nStt && nEnd == rNd.Len() )
414 : // all
415 6 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
416 3 : rArr.push_back( it->second );
417 : else
418 : {
419 109 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
420 : {
421 59 : const ::sw::mark::IMark& rBkmk = *(it->second);
422 : sal_Int32 nContent;
423 177 : if( rBkmk.GetMarkPos().nNode == nNd &&
424 101 : (nContent = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
425 : nContent < nEnd )
426 : {
427 6 : rArr.push_back( &rBkmk );
428 : }
429 121 : else if( rBkmk.IsExpanded() && nNd ==
430 30 : rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nContent =
431 77 : rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
432 : nContent < nEnd )
433 : {
434 5 : rArr.push_back( &rBkmk );
435 : }
436 : }
437 : }
438 : }
439 1006 : return !rArr.empty();
440 : }
441 :
442 : // Storage-specific
443 0 : sal_uLong StgWriter::WriteStream()
444 : {
445 : OSL_ENSURE( false, "Write in Storages on a stream?" );
446 0 : return ERR_SWG_WRITE_ERROR;
447 : }
448 :
449 32 : sal_uLong StgWriter::Write( SwPaM& rPaM, SotStorage& rStg, const OUString* pFName )
450 : {
451 32 : SetStream(0);
452 32 : pStg = &rStg;
453 32 : pDoc = rPaM.GetDoc();
454 32 : pOrigFileName = pFName;
455 :
456 : // Copy PaM, so that it can be modified
457 32 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
458 : // for comparison secure to the current Pam
459 32 : pOrigPam = &rPaM;
460 :
461 32 : sal_uLong nRet = WriteStorage();
462 :
463 32 : pStg = NULL;
464 32 : ResetWriter();
465 :
466 32 : return nRet;
467 : }
468 :
469 71 : sal_uLong StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const OUString* pFName, SfxMedium* pMedium )
470 : {
471 71 : SetStream(0);
472 71 : pStg = 0;
473 71 : xStg = rStg;
474 71 : pDoc = rPaM.GetDoc();
475 71 : pOrigFileName = pFName;
476 :
477 : // Copy PaM, so that it can be modified
478 71 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
479 : // for comparison secure to the current Pam
480 71 : pOrigPam = &rPaM;
481 :
482 71 : sal_uLong nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
483 :
484 71 : pStg = NULL;
485 71 : ResetWriter();
486 :
487 71 : return nRet;
488 177 : }
489 :
490 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|