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 <shellio.hxx>
29 : #include <doc.hxx>
30 : #include <docary.hxx>
31 : #include <IMark.hxx>
32 : #include <numrule.hxx>
33 : #include <swerror.h>
34 : #include <boost/scoped_ptr.hpp>
35 :
36 : using namespace ::com::sun::star;
37 :
38 :
39 : // Stringbuffer for the converted numbers
40 : static sal_Char aNToABuf[] = "0000000000000000000000000";
41 : #define NTOABUFLEN (sizeof(aNToABuf))
42 :
43 : typedef std::multimap<sal_uLong, const ::sw::mark::IMark*> SwBookmarkNodeTable;
44 :
45 : struct Writer_Impl
46 : {
47 : SvStream * m_pStream;
48 :
49 : boost::scoped_ptr< std::map<String, String> > pFileNameMap;
50 : std::vector<const SvxFontItem*> aFontRemoveLst;
51 : SwBookmarkNodeTable aBkmkNodePos;
52 :
53 : Writer_Impl();
54 : ~Writer_Impl();
55 :
56 : void RemoveFontList( SwDoc& rDoc );
57 : void InsertBkmk( const ::sw::mark::IMark& rBkmk );
58 : };
59 :
60 11427 : Writer_Impl::Writer_Impl()
61 11427 : : m_pStream(0)
62 : {
63 11427 : }
64 :
65 11427 : Writer_Impl::~Writer_Impl()
66 : {
67 11427 : }
68 :
69 5693 : void Writer_Impl::RemoveFontList( SwDoc& rDoc )
70 : {
71 17208 : for( std::vector<const SvxFontItem*>::const_iterator it = aFontRemoveLst.begin();
72 11472 : it != aFontRemoveLst.end(); ++it )
73 : {
74 43 : rDoc.GetAttrPool().Remove( **it );
75 : }
76 5693 : }
77 :
78 2 : void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
79 : {
80 :
81 2 : sal_uLong nNd = rBkmk.GetMarkPos().nNode.GetIndex();
82 :
83 2 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ) );
84 :
85 2 : if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
86 : {
87 0 : nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
88 0 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ));
89 : }
90 2 : }
91 :
92 : /*
93 : * This module is the central collection point for all writer-filters
94 : * and is a DLL !
95 : *
96 : * So that the Writer can work with different writers, the output-functions
97 : * of the content carrying objects have to be mapped to the various
98 : * output-functions.
99 : *
100 : * For that, to inquire its output function, every object can be gripped
101 : * via the which-value in a table.
102 : * These functions are available in the corresponding Writer-DLL's.
103 : */
104 :
105 5734 : Writer::Writer()
106 5734 : : m_pImpl(new Writer_Impl)
107 11468 : , pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
108 : {
109 5734 : bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
110 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
111 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
112 5734 : bOrganizerMode = false;
113 5734 : bExportPargraphNumbering = sal_True;
114 5734 : }
115 :
116 5734 : Writer::~Writer()
117 : {
118 5734 : }
119 :
120 : /*
121 : * Document Interface Access
122 : */
123 8 : IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return pDoc; }
124 0 : const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return pDoc; }
125 4 : IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return pDoc; }
126 0 : const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return pDoc; }
127 :
128 5693 : void Writer::ResetWriter()
129 : {
130 5693 : m_pImpl->RemoveFontList( *pDoc );
131 5693 : m_pImpl.reset(new Writer_Impl);
132 :
133 5693 : if( pCurPam )
134 : {
135 11386 : while( pCurPam->GetNext() != pCurPam )
136 0 : delete pCurPam->GetNext();
137 5693 : delete pCurPam;
138 : }
139 5693 : pCurPam = 0;
140 5693 : pOrigFileName = 0;
141 5693 : pDoc = 0;
142 :
143 5693 : bShowProgress = bUCS2_WithStartChar = sal_True;
144 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
145 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
146 5693 : bOrganizerMode = sal_False;
147 5693 : }
148 :
149 5929 : sal_Bool Writer::CopyNextPam( SwPaM ** ppPam )
150 : {
151 5929 : if( (*ppPam)->GetNext() == pOrigPam )
152 : {
153 5929 : *ppPam = pOrigPam; // set back to the beginning pam
154 5929 : return sal_False; // end of the ring
155 : }
156 :
157 : // otherwise copy the next value from the next Pam
158 0 : *ppPam = ((SwPaM*)(*ppPam)->GetNext() );
159 :
160 0 : *pCurPam->GetPoint() = *(*ppPam)->Start();
161 0 : *pCurPam->GetMark() = *(*ppPam)->End();
162 :
163 0 : return sal_True;
164 : }
165 :
166 : // search the next Bookmark-Position from the Bookmark-Table
167 :
168 523 : sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
169 : {
170 523 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
171 : const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
172 523 : pMarkAccess->getMarksBegin(),
173 523 : pMarkAccess->getMarksEnd(),
174 : rPos,
175 1046 : sw::mark::CompareIMarkStartsBefore()); // find the first Mark that does not start before
176 523 : if(ppBkmk != pMarkAccess->getMarksEnd())
177 0 : return ppBkmk - pMarkAccess->getMarksBegin();
178 523 : return -1;
179 : }
180 :
181 :
182 : SwPaM *
183 322 : Writer::NewSwPaM(SwDoc & rDoc, sal_uLong const nStartIdx, sal_uLong const nEndIdx)
184 : {
185 322 : SwNodes *const pNds = &rDoc.GetNodes();
186 :
187 322 : SwNodeIndex aStt( *pNds, nStartIdx );
188 322 : SwCntntNode* pCNode = aStt.GetNode().GetCntntNode();
189 322 : if( !pCNode && 0 == ( pCNode = pNds->GoNext( &aStt )) )
190 : {
191 : OSL_FAIL( "No more ContentNode at StartPos" );
192 : }
193 :
194 322 : SwPaM* pNew = new SwPaM( aStt );
195 322 : pNew->SetMark();
196 322 : aStt = nEndIdx;
197 322 : if( 0 == (pCNode = aStt.GetNode().GetCntntNode()) &&
198 : 0 == (pCNode = pNds->GoPrevious( &aStt )) )
199 : {
200 : OSL_FAIL( "No more ContentNode at StartPos" );
201 : }
202 322 : pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
203 322 : pNew->GetPoint()->nNode = aStt;
204 322 : return pNew;
205 : }
206 :
207 : /////////////////////////////////////////////////////////////////////////////
208 :
209 : // Stream-specific
210 45266 : SvStream& Writer::Strm()
211 : {
212 : OSL_ENSURE( m_pImpl->m_pStream, "Oh-oh. Writer with no Stream!" );
213 45266 : return *m_pImpl->m_pStream;
214 : }
215 :
216 81 : void Writer::SetStream(SvStream *const pStream)
217 81 : { m_pImpl->m_pStream = pStream; }
218 :
219 359 : SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
220 : {
221 : // Set the Pointer at the end of the buffer
222 359 : sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
223 :
224 359 : int bNeg = nVal < 0;
225 359 : if( bNeg )
226 22 : nVal = -nVal;
227 :
228 1022 : do {
229 1022 : *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
230 1022 : nVal /= 10;
231 : } while( nVal );
232 :
233 : // is the number negative, then in addition -
234 359 : if( bNeg )
235 22 : *(--pStr) = '-';
236 :
237 359 : return rStrm << pStr;
238 : }
239 :
240 2417 : SvStream& Writer::OutULong( SvStream& rStrm, sal_uLong nVal )
241 : {
242 : // Set the Pointer at the end of the buffer
243 2417 : sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
244 :
245 3320 : do {
246 3320 : *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
247 3320 : nVal /= 10;
248 : } while ( nVal );
249 2417 : return rStrm << pStr;
250 : }
251 :
252 :
253 5677 : sal_uLong Writer::Write( SwPaM& rPaM, SvStream& rStrm, const String* pFName )
254 : {
255 5677 : if ( IsStgWriter() )
256 : {
257 8 : SotStorageRef aRef = new SotStorage( rStrm );
258 8 : sal_uLong nResult = Write( rPaM, *aRef, pFName );
259 8 : if ( nResult == ERRCODE_NONE )
260 8 : aRef->Commit();
261 8 : return nResult;
262 : }
263 :
264 5669 : pDoc = rPaM.GetDoc();
265 5669 : pOrigFileName = pFName;
266 5669 : m_pImpl->m_pStream = &rStrm;
267 :
268 : // Copy PaM, so that it can be modified
269 5669 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
270 : // for comparison secure to the current Pam
271 5669 : pOrigPam = &rPaM;
272 :
273 5669 : sal_uLong nRet = WriteStream();
274 :
275 5669 : ResetWriter();
276 :
277 5669 : return nRet;
278 : }
279 :
280 11 : sal_uLong Writer::Write( SwPaM& rPam, SfxMedium& rMed, const String* pFileName )
281 : {
282 : // This method must be overloaded in SwXMLWriter a storage from medium will be used there.
283 : // The microsoft format can write to storage but the storage will be based on the stream.
284 11 : return Write( rPam, *rMed.GetOutStream(), pFileName );
285 : }
286 :
287 0 : sal_uLong Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* )
288 : {
289 : OSL_ENSURE( !this, "Write in Storages on a stream?" );
290 0 : return ERR_SWG_WRITE_ERROR;
291 : }
292 :
293 0 : sal_uLong Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const String*, SfxMedium* )
294 : {
295 : OSL_ENSURE( !this, "Write in Storages on a stream?" );
296 0 : return ERR_SWG_WRITE_ERROR;
297 : }
298 :
299 0 : sal_Bool Writer::CopyLocalFileToINet( String& rFileNm )
300 : {
301 0 : if( !pOrigFileName ) // can be happen, by example if we
302 0 : return sal_False; // write into the clipboard
303 :
304 0 : sal_Bool bRet = sal_False;
305 0 : INetURLObject aFileUrl( rFileNm ), aTargetUrl( *pOrigFileName );
306 :
307 : // this is our old without the Mail-Export
308 0 : if( ! ( INET_PROT_FILE == aFileUrl.GetProtocol() &&
309 0 : INET_PROT_FILE != aTargetUrl.GetProtocol() &&
310 0 : INET_PROT_FTP <= aTargetUrl.GetProtocol() &&
311 0 : INET_PROT_NEWS >= aTargetUrl.GetProtocol() ) )
312 0 : return bRet;
313 :
314 0 : if (m_pImpl->pFileNameMap)
315 : {
316 : // has the file been moved?
317 0 : std::map<String, String>::iterator it = m_pImpl->pFileNameMap->find( rFileNm );
318 0 : if ( it != m_pImpl->pFileNameMap->end() )
319 : {
320 0 : rFileNm = it->second;
321 0 : return sal_True;
322 : }
323 : }
324 : else
325 : {
326 0 : m_pImpl->pFileNameMap.reset( new std::map<String, String>() );
327 : }
328 :
329 0 : String aSrc = rFileNm;
330 0 : String aDest = aTargetUrl.GetPartBeforeLastName();
331 0 : aDest += String(aFileUrl.GetName());
332 :
333 0 : SfxMedium aSrcFile( aSrc, STREAM_READ );
334 0 : SfxMedium aDstFile( aDest, STREAM_WRITE | STREAM_SHARE_DENYNONE );
335 :
336 0 : *aDstFile.GetOutStream() << *aSrcFile.GetInStream();
337 :
338 0 : aSrcFile.Close();
339 0 : aDstFile.Commit();
340 :
341 0 : bRet = 0 == aDstFile.GetError();
342 :
343 0 : if( bRet )
344 : {
345 0 : m_pImpl->pFileNameMap->insert( std::make_pair( aSrc, aDest ) );
346 0 : rFileNm = aDest;
347 : }
348 :
349 0 : return bRet;
350 : }
351 :
352 16 : void Writer::PutNumFmtFontsInAttrPool()
353 : {
354 : // then there are a few fonts in the NumRules
355 : // These put into the Pool. After this does they have a RefCount > 1
356 : // it can be removed - it is already in the Pool
357 16 : SfxItemPool& rPool = pDoc->GetAttrPool();
358 16 : const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
359 : const SwNumRule* pRule;
360 : const SwNumFmt* pFmt;
361 : const Font* pFont;
362 16 : const Font* pDefFont = &numfunc::GetDefBulletFont();
363 16 : bool bCheck = false;
364 :
365 84 : for( sal_uInt16 nGet = rListTbl.size(); nGet; )
366 52 : if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
367 0 : for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
368 0 : if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
369 0 : SVX_NUM_BITMAP == pFmt->GetNumberingType() )
370 : {
371 0 : if( 0 == ( pFont = pFmt->GetBulletFont() ) )
372 0 : pFont = pDefFont;
373 :
374 0 : if( bCheck )
375 : {
376 0 : if( *pFont == *pDefFont )
377 0 : continue;
378 : }
379 0 : else if( *pFont == *pDefFont )
380 0 : bCheck = true;
381 :
382 : _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
383 0 : pFont->GetName(), pFont->GetStyleName(),
384 0 : pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
385 : }
386 16 : }
387 :
388 16 : void Writer::PutEditEngFontsInAttrPool( bool bIncl_CJK_CTL )
389 : {
390 16 : SfxItemPool& rPool = pDoc->GetAttrPool();
391 16 : if( rPool.GetSecondaryPool() )
392 : {
393 15 : _AddFontItems( rPool, EE_CHAR_FONTINFO );
394 15 : if( bIncl_CJK_CTL )
395 : {
396 15 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
397 15 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
398 : }
399 : }
400 16 : }
401 :
402 45 : void Writer::_AddFontItems( SfxItemPool& rPool, sal_uInt16 nW )
403 : {
404 45 : const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
405 45 : _AddFontItem( rPool, *pFont );
406 :
407 45 : if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
408 45 : _AddFontItem( rPool, *pFont );
409 :
410 45 : sal_uInt32 nMaxItem = rPool.GetItemCount2( nW );
411 51 : for( sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet )
412 6 : if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem2( nW, nGet )) )
413 6 : _AddFontItem( rPool, *pFont );
414 45 : }
415 :
416 96 : void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
417 : {
418 : const SvxFontItem* pItem;
419 96 : if( RES_CHRATR_FONT != rFont.Which() )
420 : {
421 96 : SvxFontItem aFont( rFont );
422 96 : aFont.SetWhich( RES_CHRATR_FONT );
423 96 : pItem = (SvxFontItem*)&rPool.Put( aFont );
424 : }
425 : else
426 0 : pItem = (SvxFontItem*)&rPool.Put( rFont );
427 :
428 96 : if( 1 < pItem->GetRefCount() )
429 53 : rPool.Remove( *pItem );
430 : else
431 : {
432 43 : m_pImpl->aFontRemoveLst.push_back( pItem );
433 : }
434 96 : }
435 :
436 : // build a bookmark table, which is sort by the node position. The
437 : // OtherPos of the bookmarks also inserted.
438 8 : void Writer::CreateBookmarkTbl()
439 : {
440 8 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
441 30 : for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
442 20 : ppBkmk != pMarkAccess->getBookmarksEnd();
443 : ++ppBkmk)
444 : {
445 2 : m_pImpl->InsertBkmk(**ppBkmk);
446 : }
447 8 : }
448 :
449 :
450 : // search alle Bookmarks in the range and return it in the Array
451 622 : sal_uInt16 Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt,
452 : xub_StrLen nEnd, std::vector< const ::sw::mark::IMark* >& rArr)
453 : {
454 : OSL_ENSURE( rArr.empty(), "there are still entries available" );
455 :
456 622 : sal_uLong nNd = rNd.GetIndex();
457 : std::pair<SwBookmarkNodeTable::const_iterator, SwBookmarkNodeTable::const_iterator> aIterPair
458 622 : = m_pImpl->aBkmkNodePos.equal_range( nNd );
459 622 : if( aIterPair.first != aIterPair.second )
460 : {
461 : // there exist some bookmarks, search now all which is in the range
462 4 : if( !nStt && nEnd == rNd.Len() )
463 : // all
464 0 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
465 0 : rArr.push_back( it->second );
466 : else
467 : {
468 12 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
469 : {
470 8 : const ::sw::mark::IMark& rBkmk = *(it->second);
471 : xub_StrLen nCntnt;
472 24 : if( rBkmk.GetMarkPos().nNode == nNd &&
473 10 : (nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
474 : nCntnt < nEnd )
475 : {
476 2 : rArr.push_back( &rBkmk );
477 : }
478 18 : else if( rBkmk.IsExpanded() && nNd ==
479 12 : rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
480 14 : rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
481 : nCntnt < nEnd )
482 : {
483 2 : rArr.push_back( &rBkmk );
484 : }
485 : }
486 : }
487 : }
488 622 : return rArr.size();
489 : }
490 :
491 : ////////////////////////////////////////////////////////////////////////////
492 :
493 : // Storage-specific
494 :
495 0 : sal_uLong StgWriter::WriteStream()
496 : {
497 : OSL_ENSURE( !this, "Write in Storages on a stream?" );
498 0 : return ERR_SWG_WRITE_ERROR;
499 : }
500 :
501 8 : sal_uLong StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const String* pFName )
502 : {
503 8 : SetStream(0);
504 8 : pStg = &rStg;
505 8 : pDoc = rPaM.GetDoc();
506 8 : pOrigFileName = pFName;
507 :
508 : // Copy PaM, so that it can be modified
509 8 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
510 : // for comparison secure to the current Pam
511 8 : pOrigPam = &rPaM;
512 :
513 8 : sal_uLong nRet = WriteStorage();
514 :
515 8 : pStg = NULL;
516 8 : ResetWriter();
517 :
518 8 : return nRet;
519 : }
520 :
521 16 : sal_uLong StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const String* pFName, SfxMedium* pMedium )
522 : {
523 16 : SetStream(0);
524 16 : pStg = 0;
525 16 : xStg = rStg;
526 16 : pDoc = rPaM.GetDoc();
527 16 : pOrigFileName = pFName;
528 :
529 : // Copy PaM, so that it can be modified
530 16 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
531 : // for comparison secure to the current Pam
532 16 : pOrigPam = &rPaM;
533 :
534 16 : sal_uLong nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
535 :
536 16 : pStg = NULL;
537 16 : ResetWriter();
538 :
539 16 : return nRet;
540 99 : }
541 :
542 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|