bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / ww8par.cxx
blob645d2466e7f479b50b5d4875a280a8c85a3e725a
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 .
21 #include <com/sun/star/embed/ElementModes.hpp>
23 #include <i18nlangtag/languagetag.hxx>
25 #include <unotools/ucbstreamhelper.hxx>
26 #include <rtl/random.h>
28 #include <sfx2/docinf.hxx>
29 #include <sfx2/request.hxx>
30 #include <sfx2/frame.hxx>
31 #include <tools/urlobj.hxx>
32 #include <unotools/tempfile.hxx>
34 #include <comphelper/docpasswordrequest.hxx>
35 #include <comphelper/string.hxx>
37 #include <editeng/brushitem.hxx>
38 #include <editeng/tstpitem.hxx>
39 #include <editeng/ulspitem.hxx>
40 #include <editeng/langitem.hxx>
41 #include <editeng/opaqitem.hxx>
42 #include <editeng/charhiddenitem.hxx>
43 #include <editeng/fontitem.hxx>
44 #include <svx/unoapi.hxx>
45 #include <svx/svdoole2.hxx>
46 #include <svx/svdoashp.hxx>
47 #include <svx/svxerr.hxx>
48 #include <filter/msfilter/mscodec.hxx>
49 #include <svx/svdmodel.hxx>
50 #include <svx/xflclit.hxx>
52 #include <unotools/fltrcfg.hxx>
53 #include <fmtfld.hxx>
54 #include <fmturl.hxx>
55 #include <fmtinfmt.hxx>
56 #include <reffld.hxx>
57 #include <fmthdft.hxx>
58 #include <fmtcntnt.hxx>
59 #include <fmtcnct.hxx>
60 #include <fmtanchr.hxx>
61 #include <fmtpdsc.hxx>
62 #include <ftninfo.hxx>
63 #include <fmtftn.hxx>
64 #include <txtftn.hxx>
65 #include <ndtxt.hxx> // class SwTxtNode
66 #include <pagedesc.hxx> // class SwPageDesc
67 #include <paratr.hxx>
68 #include <fmtclbl.hxx>
69 #include <section.hxx>
70 #include <docsh.hxx>
71 #include <docufld.hxx>
72 #include <swfltopt.hxx>
73 #include <viewsh.hxx>
74 #include <shellres.hxx>
75 #include <mdiexp.hxx> // Progress
76 #include <statstr.hrc> // ResId fuer Statusleiste
77 #include <swerror.h> // ERR_WW8_...
78 #include <swtable.hxx> // class SwTableLines, ...
79 #include <fchrfmt.hxx>
80 #include <charfmt.hxx>
83 #include <comphelper/extract.hxx>
84 #include <fltini.hxx>
86 #include "writerwordglue.hxx"
88 #include "ndgrf.hxx"
89 #include <editeng/editids.hrc>
90 #include <txtflcnt.hxx>
91 #include <fmtflcnt.hxx>
92 #include <txatbase.hxx>
94 #include "ww8par2.hxx" // class WW8RStyle, class WW8AnchorPara
96 #include <com/sun/star/beans/PropertyAttribute.hpp>
97 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
98 #include <com/sun/star/document/XViewDataSupplier.hpp>
99 #include <com/sun/star/document/IndexedPropertyValues.hpp>
100 #include <svl/itemiter.hxx> //SfxItemIter
102 #include <comphelper/processfactory.hxx>
103 #include <basic/basmgr.hxx>
105 #include "ww8toolbar.hxx"
106 #include <osl/file.hxx>
108 #include <breakit.hxx>
110 #if OSL_DEBUG_LEVEL > 1
111 #include <iostream>
112 #include <dbgoutsw.hxx>
113 #endif
114 #include <unotools/localfilehelper.hxx>
116 #include "WW8Sttbf.hxx"
117 #include "WW8FibData.hxx"
119 using namespace ::com::sun::star;
120 using namespace sw::util;
121 using namespace sw::types;
122 using namespace nsHdFtFlags;
124 #include <com/sun/star/i18n/ScriptType.hpp>
125 #include <unotools/pathoptions.hxx>
126 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
128 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
129 #include <comphelper/mediadescriptor.hxx>
130 #include <oox/ole/vbaproject.hxx>
131 #include <oox/ole/olestorage.hxx>
133 using ::comphelper::MediaDescriptor;
135 class BasicProjImportHelper
137 SwDocShell& mrDocShell;
138 uno::Reference< uno::XComponentContext > mxCtx;
139 public:
140 BasicProjImportHelper( SwDocShell& rShell ) : mrDocShell( rShell )
142 mxCtx = comphelper::getProcessComponentContext();
144 bool import( const uno::Reference< io::XInputStream >& rxIn );
145 OUString getProjectName();
148 bool BasicProjImportHelper::import( const uno::Reference< io::XInputStream >& rxIn )
150 bool bRet = false;
153 oox::ole::OleStorage root( mxCtx, rxIn, false );
154 oox::StorageRef vbaStg = root.openSubStorage( "Macros" , false );
155 if ( vbaStg.get() )
157 oox::ole::VbaProject aVbaPrj( mxCtx, mrDocShell.GetModel(), OUString("Writer") );
158 bRet = aVbaPrj.importVbaProject( *vbaStg );
161 catch( const uno::Exception& )
163 bRet = false;
165 return bRet;
168 OUString BasicProjImportHelper::getProjectName()
170 OUString sProjName( "Standard" );
171 uno::Reference< beans::XPropertySet > xProps( mrDocShell.GetModel(), uno::UNO_QUERY );
172 if ( xProps.is() )
176 uno::Reference< script::vba::XVBACompatibility > xVBA( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
177 sProjName = xVBA->getProjectName();
180 catch( const uno::Exception& )
184 return sProjName;
188 class Sttb : TBBase
190 struct SBBItem
192 sal_uInt16 cchData;
193 OUString data;
194 SBBItem() : cchData(0){}
196 sal_uInt16 fExtend;
197 sal_uInt16 cData;
198 sal_uInt16 cbExtra;
200 std::vector< SBBItem > dataItems;
202 Sttb(const Sttb&);
203 Sttb& operator = ( const Sttb&);
204 public:
205 Sttb();
206 ~Sttb();
207 bool Read(SvStream &rS);
208 void Print( FILE* fp );
209 OUString getStringAtIndex( sal_uInt32 );
212 Sttb::Sttb() : fExtend( 0 )
213 ,cData( 0 )
214 ,cbExtra( 0 )
218 Sttb::~Sttb()
222 bool Sttb::Read( SvStream& rS )
224 OSL_TRACE("Sttb::Read() stream pos 0x%x", rS.Tell() );
225 nOffSet = rS.Tell();
226 rS >> fExtend >> cData >> cbExtra;
227 if ( cData )
229 for ( sal_Int32 index = 0; index < cData; ++index )
231 SBBItem aItem;
232 rS >> aItem.cchData;
233 aItem.data = read_uInt16s_ToOUString(rS, aItem.cchData);
234 dataItems.push_back( aItem );
237 return true;
240 void Sttb::Print( FILE* fp )
242 fprintf( fp, "[ 0x%" SAL_PRIxUINT32 " ] Sttb - dump\n", nOffSet);
243 fprintf( fp, " fExtend 0x%x [expected 0xFFFF ]\n", fExtend );
244 fprintf( fp, " cData no. or string data items %d (0x%x)\n", cData, cData );
246 if ( cData )
248 for ( sal_Int32 index = 0; index < cData; ++index )
249 fprintf(fp," string dataItem[ %d(0x%x) ] has name %s\n", static_cast< int >( index ), static_cast< unsigned int >( index ), OUStringToOString( dataItems[ index ].data, RTL_TEXTENCODING_UTF8 ).getStr() );
254 OUString
255 Sttb::getStringAtIndex( sal_uInt32 index )
257 OUString aRet;
258 if ( index < dataItems.size() )
259 aRet = dataItems[ index ].data;
260 return aRet;
263 SwMSDffManager::SwMSDffManager( SwWW8ImplReader& rRdr )
264 : SvxMSDffManager(*rRdr.pTableStream, rRdr.GetBaseURL(), rRdr.pWwFib->fcDggInfo,
265 rRdr.pDataStream, 0, 0, COL_WHITE, 12, rRdr.pStrm),
266 rReader(rRdr), pFallbackStream(0)
268 SetSvxMSDffSettings( GetSvxMSDffSettings() );
269 nSvxMSDffOLEConvFlags = SwMSDffManager::GetFilterFlags();
272 sal_uInt32 SwMSDffManager::GetFilterFlags()
274 sal_uInt32 nFlags(0);
275 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
276 if (rOpt.IsMathType2Math())
277 nFlags |= OLE_MATHTYPE_2_STARMATH;
278 if (rOpt.IsExcel2Calc())
279 nFlags |= OLE_EXCEL_2_STARCALC;
280 if (rOpt.IsPowerPoint2Impress())
281 nFlags |= OLE_POWERPOINT_2_STARIMPRESS;
282 if (rOpt.IsWinWord2Writer())
283 nFlags |= OLE_WINWORD_2_STARWRITER;
284 return nFlags;
288 * I would like to override the default OLE importing to add a test
289 * and conversion of OCX controls from their native OLE type into our
290 * native nonOLE Form Control Objects.
292 * cmc
294 // #i32596# - consider new parameter <_nCalledByGroup>
295 SdrObject* SwMSDffManager::ImportOLE( long nOLEId,
296 const Graphic& rGrf,
297 const Rectangle& rBoundRect,
298 const Rectangle& rVisArea,
299 const int _nCalledByGroup,
300 sal_Int64 nAspect ) const
302 // #i32596# - no import of OLE object, if it's inside a group.
303 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
304 // if drawing OLE objects are allowed in Writer.
305 if ( _nCalledByGroup > 0 )
307 return 0L;
310 SdrObject* pRet = 0;
311 OUString sStorageName;
312 SotStorageRef xSrcStg;
313 uno::Reference < embed::XStorage > xDstStg;
314 if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
316 SvStorageRef xSrc = xSrcStg->OpenSotStorage( sStorageName,
317 STREAM_READWRITE| STREAM_SHARE_DENYALL );
318 OSL_ENSURE(rReader.pFormImpl, "No Form Implementation!");
319 ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape;
320 if ( (!(rReader.bIsHeader || rReader.bIsFooter)) &&
321 rReader.pFormImpl->ReadOCXStream(xSrc,&xShape,true))
323 pRet = GetSdrObjectFromXShape(xShape);
325 else
327 ErrCode nError = ERRCODE_NONE;
328 pRet = CreateSdrOLEFromStorage( sStorageName, xSrcStg, xDstStg,
329 rGrf, rBoundRect, rVisArea, pStData, nError, nSvxMSDffOLEConvFlags, nAspect );
332 return pRet;
335 void SwMSDffManager::DisableFallbackStream()
337 OSL_ENSURE(!pFallbackStream,
338 "if you're recursive, you're broken");
339 pFallbackStream = pStData2;
340 aOldEscherBlipCache = aEscherBlipCache;
341 aEscherBlipCache.clear();
342 pStData2 = 0;
345 void SwMSDffManager::EnableFallbackStream()
347 pStData2 = pFallbackStream;
348 aEscherBlipCache = aOldEscherBlipCache;
349 aOldEscherBlipCache.clear();
350 pFallbackStream = 0;
353 sal_uInt16 SwWW8ImplReader::GetToggleAttrFlags() const
355 return pCtrlStck ? pCtrlStck->GetToggleAttrFlags() : 0;
358 sal_uInt16 SwWW8ImplReader::GetToggleBiDiAttrFlags() const
360 return pCtrlStck ? pCtrlStck->GetToggleBiDiAttrFlags() : 0;
363 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags)
365 if (pCtrlStck)
366 pCtrlStck->SetToggleAttrFlags(nFlags);
369 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags)
371 if (pCtrlStck)
372 pCtrlStck->SetToggleBiDiAttrFlags(nFlags);
376 SdrObject* SwMSDffManager::ProcessObj(SvStream& rSt,
377 DffObjData& rObjData,
378 void* pData,
379 Rectangle& rTextRect,
380 SdrObject* pObj
383 if( !rTextRect.IsEmpty() )
385 SvxMSDffImportData& rImportData = *(SvxMSDffImportData*)pData;
386 SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec;
388 // fill Import Record with data
389 pImpRec->nShapeId = rObjData.nShapeId;
390 pImpRec->eShapeType = rObjData.eShapeType;
392 rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
393 DFF_msofbtClientAnchor,
394 SEEK_FROM_CURRENT_AND_RESTART );
395 if( rObjData.bClientAnchor )
396 ProcessClientAnchor( rSt,
397 maShapeRecords.Current()->nRecLen,
398 pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
400 rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
401 DFF_msofbtClientData,
402 SEEK_FROM_CURRENT_AND_RESTART );
403 if( rObjData.bClientData )
404 ProcessClientData( rSt,
405 maShapeRecords.Current()->nRecLen,
406 pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
409 // process user (== Winword) defined parameters in 0xF122 record
410 // #i84783# - set special value to determine, if property is provided or not.
411 pImpRec->nLayoutInTableCell = 0xFFFFFFFF;
413 if( maShapeRecords.SeekToContent( rSt,
414 DFF_msofbtUDefProp,
415 SEEK_FROM_CURRENT_AND_RESTART )
416 && maShapeRecords.Current()->nRecLen )
418 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
419 sal_uInt32 nUDData;
420 sal_uInt16 nPID;
421 while( 5 < nBytesLeft )
423 rSt >> nPID;
424 if ( rSt.GetError() != 0 )
425 break;
426 rSt >> nUDData;
427 switch( nPID )
429 case 0x038F: pImpRec->nXAlign = nUDData; break;
430 case 0x0390:
431 delete pImpRec->pXRelTo;
432 pImpRec->pXRelTo = new sal_uInt32;
433 *(pImpRec->pXRelTo) = nUDData;
434 break;
435 case 0x0391: pImpRec->nYAlign = nUDData; break;
436 case 0x0392:
437 delete pImpRec->pYRelTo;
438 pImpRec->pYRelTo = new sal_uInt32;
439 *(pImpRec->pYRelTo) = nUDData;
440 break;
441 case 0x03BF: pImpRec->nLayoutInTableCell = nUDData; break;
442 case 0x0393:
443 // This seems to correspond to o:hrpct from .docx (even including
444 // the difference that it's in 0.1% even though the .docx spec
445 // says it's in 1%).
446 pImpRec->relativeHorizontalWidth = nUDData;
447 break;
448 case 0x0394:
449 // And this is really just a guess, but a mere presence of this
450 // flag makes a horizontal rule be as wide as the page (unless
451 // overriden by something), so it probably matches o:hr from .docx.
452 pImpRec->isHorizontalRule = true;
453 break;
455 if ( rSt.GetError() != 0 )
456 break;
457 pImpRec->bHasUDefProp = sal_True;
458 nBytesLeft -= 6;
462 // Textrahmen, auch Title oder Outline
463 sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
464 if( nTextId )
466 SfxItemSet aSet( pSdrModel->GetItemPool() );
468 //Originally anything that as a mso_sptTextBox was created as a
469 //textbox, this was changed for #88277# to be created as a simple
470 //rect to keep impress happy. For the rest of us we'd like to turn
471 //it back into a textbox again.
472 bool bIsSimpleDrawingTextBox = (pImpRec->eShapeType == mso_sptTextBox);
473 if (!bIsSimpleDrawingTextBox)
475 //Either
476 //a) its a simple text object or
477 //b) its a rectangle with text and square wrapping.
478 bIsSimpleDrawingTextBox =
480 (pImpRec->eShapeType == mso_sptTextSimple) ||
482 (pImpRec->eShapeType == mso_sptRectangle)
483 && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
488 // Distance of Textbox to it's surrounding Autoshape
489 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L);
490 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L );
491 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L );
492 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L );
494 ScaleEmu( nTextLeft );
495 ScaleEmu( nTextRight );
496 ScaleEmu( nTextTop );
497 ScaleEmu( nTextBottom );
499 sal_Int32 nTextRotationAngle=0;
500 bool bVerticalText = false;
501 if ( IsProperty( DFF_Prop_txflTextFlow ) )
503 MSO_TextFlow eTextFlow = (MSO_TextFlow)(GetPropertyValue(
504 DFF_Prop_txflTextFlow) & 0xFFFF);
505 switch( eTextFlow )
507 case mso_txflBtoT:
508 nTextRotationAngle = 9000;
509 break;
510 case mso_txflVertN:
511 case mso_txflTtoBN:
512 nTextRotationAngle = 27000;
513 break;
514 case mso_txflTtoBA:
515 bVerticalText = true;
516 break;
517 case mso_txflHorzA:
518 bVerticalText = true;
519 nTextRotationAngle = 9000;
520 case mso_txflHorzN:
521 default :
522 break;
526 if (nTextRotationAngle)
528 while (nTextRotationAngle > 360000)
529 nTextRotationAngle-=9000;
530 switch (nTextRotationAngle)
532 case 9000:
534 long nWidth = rTextRect.GetWidth();
535 rTextRect.Right() = rTextRect.Left() + rTextRect.GetHeight();
536 rTextRect.Bottom() = rTextRect.Top() + nWidth;
538 sal_Int32 nOldTextLeft = nTextLeft;
539 sal_Int32 nOldTextRight = nTextRight;
540 sal_Int32 nOldTextTop = nTextTop;
541 sal_Int32 nOldTextBottom = nTextBottom;
543 nTextLeft = nOldTextBottom;
544 nTextRight = nOldTextTop;
545 nTextTop = nOldTextLeft;
546 nTextBottom = nOldTextRight;
548 break;
549 case 27000:
551 long nWidth = rTextRect.GetWidth();
552 rTextRect.Right() = rTextRect.Left() + rTextRect.GetHeight();
553 rTextRect.Bottom() = rTextRect.Top() + nWidth;
555 sal_Int32 nOldTextLeft = nTextLeft;
556 sal_Int32 nOldTextRight = nTextRight;
557 sal_Int32 nOldTextTop = nTextTop;
558 sal_Int32 nOldTextBottom = nTextBottom;
560 nTextLeft = nOldTextTop;
561 nTextRight = nOldTextBottom;
562 nTextTop = nOldTextRight;
563 nTextBottom = nOldTextLeft;
565 break;
566 default:
567 break;
571 if (bIsSimpleDrawingTextBox)
573 SdrObject::Free( pObj );
574 pObj = new SdrRectObj(OBJ_TEXT, rTextRect);
577 // Die vertikalen Absatzeinrueckungen sind im BoundRect mit drin,
578 // hier rausrechnen
579 Rectangle aNewRect(rTextRect);
580 aNewRect.Bottom() -= nTextTop + nTextBottom;
581 aNewRect.Right() -= nTextLeft + nTextRight;
583 // Nur falls es eine einfache Textbox ist, darf der Writer
584 // das Objekt durch einen Rahmen ersetzen, ansonsten
585 if( bIsSimpleDrawingTextBox )
587 ::boost::shared_ptr<SvxMSDffShapeInfo> const pTmpRec(
588 new SvxMSDffShapeInfo(0, pImpRec->nShapeId));
590 SvxMSDffShapeInfos_ById::const_iterator const it =
591 GetShapeInfos()->find(pTmpRec);
592 if (it != GetShapeInfos()->end())
594 SvxMSDffShapeInfo& rInfo = **it;
595 pImpRec->bReplaceByFly = rInfo.bReplaceByFly;
596 pImpRec->bLastBoxInChain = rInfo.bLastBoxInChain;
600 if( bIsSimpleDrawingTextBox )
601 ApplyAttributes( rSt, aSet, rObjData );
603 if (GetPropertyValue(DFF_Prop_FitTextToShape) & 2)
605 aSet.Put( SdrTextAutoGrowHeightItem( sal_True ) );
606 aSet.Put( SdrTextMinFrameHeightItem(
607 aNewRect.Bottom() - aNewRect.Top() ) );
608 aSet.Put( SdrTextMinFrameWidthItem(
609 aNewRect.Right() - aNewRect.Left() ) );
611 else
613 aSet.Put( SdrTextAutoGrowHeightItem( sal_False ) );
614 aSet.Put( SdrTextAutoGrowWidthItem( sal_False ) );
617 switch ( (MSO_WrapMode)
618 GetPropertyValue( DFF_Prop_WrapText, mso_wrapSquare ) )
620 case mso_wrapNone :
621 aSet.Put( SdrTextAutoGrowWidthItem( sal_True ) );
622 pImpRec->bAutoWidth = true;
623 break;
624 case mso_wrapByPoints :
625 aSet.Put( SdrTextContourFrameItem( sal_True ) );
626 break;
627 default:
631 // Abstaende an den Raendern der Textbox setzen
632 aSet.Put( SdrTextLeftDistItem( nTextLeft ) );
633 aSet.Put( SdrTextRightDistItem( nTextRight ) );
634 aSet.Put( SdrTextUpperDistItem( nTextTop ) );
635 aSet.Put( SdrTextLowerDistItem( nTextBottom ) );
636 pImpRec->nDxTextLeft = nTextLeft;
637 pImpRec->nDyTextTop = nTextTop;
638 pImpRec->nDxTextRight = nTextRight;
639 pImpRec->nDyTextBottom = nTextBottom;
641 // taking the correct default (which is mso_anchorTop)
642 MSO_Anchor eTextAnchor =
643 (MSO_Anchor)GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
645 SdrTextVertAdjust eTVA = bVerticalText
646 ? SDRTEXTVERTADJUST_BLOCK
647 : SDRTEXTVERTADJUST_CENTER;
648 SdrTextHorzAdjust eTHA = bVerticalText
649 ? SDRTEXTHORZADJUST_CENTER
650 : SDRTEXTHORZADJUST_BLOCK;
652 switch( eTextAnchor )
654 case mso_anchorTop:
656 if ( bVerticalText )
657 eTHA = SDRTEXTHORZADJUST_RIGHT;
658 else
659 eTVA = SDRTEXTVERTADJUST_TOP;
661 break;
662 case mso_anchorTopCentered:
664 if ( bVerticalText )
665 eTHA = SDRTEXTHORZADJUST_RIGHT;
666 else
667 eTVA = SDRTEXTVERTADJUST_TOP;
669 break;
670 case mso_anchorMiddle:
671 break;
672 case mso_anchorMiddleCentered:
673 break;
674 case mso_anchorBottom:
676 if ( bVerticalText )
677 eTHA = SDRTEXTHORZADJUST_LEFT;
678 else
679 eTVA = SDRTEXTVERTADJUST_BOTTOM;
681 break;
682 case mso_anchorBottomCentered:
684 if ( bVerticalText )
685 eTHA = SDRTEXTHORZADJUST_LEFT;
686 else
687 eTVA = SDRTEXTVERTADJUST_BOTTOM;
689 break;
690 default:
694 aSet.Put( SdrTextVertAdjustItem( eTVA ) );
695 aSet.Put( SdrTextHorzAdjustItem( eTHA ) );
697 if (pObj != NULL)
699 pObj->SetMergedItemSet(aSet);
700 pObj->SetModel(pSdrModel);
702 if (bVerticalText && dynamic_cast< SdrTextObj* >( pObj ) )
703 dynamic_cast< SdrTextObj* >( pObj )->SetVerticalWriting(sal_True);
705 if ( bIsSimpleDrawingTextBox )
707 if ( nTextRotationAngle )
709 long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
710 rTextRect.GetWidth() : rTextRect.GetHeight();
711 nMinWH /= 2;
712 Point aPivot(rTextRect.TopLeft());
713 aPivot.X() += nMinWH;
714 aPivot.Y() += nMinWH;
715 double a = nTextRotationAngle * nPi180;
716 pObj->NbcRotate(aPivot, nTextRotationAngle, sin(a), cos(a));
720 if ( ( ( rObjData.nSpFlags & SP_FFLIPV ) || mnFix16Angle || nTextRotationAngle ) && dynamic_cast< SdrObjCustomShape* >( pObj ) )
722 SdrObjCustomShape* pCustomShape = dynamic_cast< SdrObjCustomShape* >( pObj );
724 double fExtraTextRotation = 0.0;
725 if ( mnFix16Angle && !( GetPropertyValue( DFF_Prop_FitTextToShape ) & 4 ) )
726 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
727 fExtraTextRotation = -mnFix16Angle;
729 if ( rObjData.nSpFlags & SP_FFLIPV ) // sj: in ppt the text is flipped, whereas in word the text
730 { // remains unchanged, so we have to take back the flipping here
731 fExtraTextRotation += 18000.0; // because our core will flip text if the shape is flipped.
733 fExtraTextRotation += nTextRotationAngle;
734 if ( !::basegfx::fTools::equalZero( fExtraTextRotation ) )
736 fExtraTextRotation /= 100.0;
737 SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
738 const OUString sTextRotateAngle( "TextRotateAngle" );
739 com::sun::star::beans::PropertyValue aPropVal;
740 aPropVal.Name = sTextRotateAngle;
741 aPropVal.Value <<= fExtraTextRotation;
742 aGeometryItem.SetPropertyValue( aPropVal );
743 pCustomShape->SetMergedItem( aGeometryItem );
746 else if ( mnFix16Angle )
748 // rotate text with shape ?
749 double a = mnFix16Angle * nPi180;
750 pObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
751 sin( a ), cos( a ) );
755 else if( !pObj )
757 // simple rectangular objects are ignored by ImportObj() :-(
758 // this is OK for Draw but not for Calc and Writer
759 // cause here these objects have a default border
760 pObj = new SdrRectObj(rTextRect);
761 pObj->SetModel( pSdrModel );
762 SfxItemSet aSet( pSdrModel->GetItemPool() );
763 ApplyAttributes( rSt, aSet, rObjData );
765 const SfxPoolItem* pPoolItem=NULL;
766 SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR,
767 sal_False, &pPoolItem );
768 if( SFX_ITEM_DEFAULT == eState )
769 aSet.Put( XFillColorItem( String(),
770 Color( mnDefaultColor ) ) );
771 pObj->SetMergedItemSet(aSet);
774 //Means that fBehindDocument is set
775 if (GetPropertyValue(DFF_Prop_fPrint) & 0x20)
776 pImpRec->bDrawHell = sal_True;
777 else
778 pImpRec->bDrawHell = sal_False;
779 if (GetPropertyValue(DFF_Prop_fPrint) & 0x02)
780 pImpRec->bHidden = sal_True;
781 pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 );
783 if ( nTextId )
785 pImpRec->aTextId.nTxBxS = (sal_uInt16)( nTextId >> 16 );
786 pImpRec->aTextId.nSequence = (sal_uInt16)nTextId;
789 pImpRec->nDxWrapDistLeft = GetPropertyValue(
790 DFF_Prop_dxWrapDistLeft, 114935L ) / 635L;
791 pImpRec->nDyWrapDistTop = GetPropertyValue(
792 DFF_Prop_dyWrapDistTop, 0 ) / 635L;
793 pImpRec->nDxWrapDistRight = GetPropertyValue(
794 DFF_Prop_dxWrapDistRight, 114935L ) / 635L;
795 pImpRec->nDyWrapDistBottom = GetPropertyValue(
796 DFF_Prop_dyWrapDistBottom, 0 ) / 635L;
797 // 16.16 fraction times total image width or height, as appropriate.
799 if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
801 delete pImpRec->pWrapPolygon;
802 pImpRec->pWrapPolygon = NULL;
804 sal_uInt16 nNumElemVert, nNumElemMemVert, nElemSizeVert;
805 rSt >> nNumElemVert >> nNumElemMemVert >> nElemSizeVert;
806 if (nNumElemVert && ((nElemSizeVert == 8) || (nElemSizeVert == 4)))
808 pImpRec->pWrapPolygon = new Polygon(nNumElemVert);
809 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
811 sal_Int32 nX, nY;
812 if (nElemSizeVert == 8)
813 rSt >> nX >> nY;
814 else
816 sal_Int16 nSmallX, nSmallY;
817 rSt >> nSmallX >> nSmallY;
818 nX = nSmallX;
819 nY = nSmallY;
821 (*(pImpRec->pWrapPolygon))[i].X() = nX;
822 (*(pImpRec->pWrapPolygon))[i].Y() = nY;
827 pImpRec->nCropFromTop = GetPropertyValue(
828 DFF_Prop_cropFromTop, 0 );
829 pImpRec->nCropFromBottom = GetPropertyValue(
830 DFF_Prop_cropFromBottom, 0 );
831 pImpRec->nCropFromLeft = GetPropertyValue(
832 DFF_Prop_cropFromLeft, 0 );
833 pImpRec->nCropFromRight = GetPropertyValue(
834 DFF_Prop_cropFromRight, 0 );
836 sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash );
838 if ( !IsHardAttribute( DFF_Prop_fLine ) &&
839 pImpRec->eShapeType == mso_sptPictureFrame )
841 nLineFlags &= ~0x08;
844 pImpRec->eLineStyle = (nLineFlags & 8)
845 ? (MSO_LineStyle)GetPropertyValue(
846 DFF_Prop_lineStyle,
847 mso_lineSimple )
848 : (MSO_LineStyle)USHRT_MAX;
849 pImpRec->eLineDashing = (MSO_LineDashing)GetPropertyValue(
850 DFF_Prop_lineDashing, mso_lineSolid );
852 pImpRec->nFlags = rObjData.nSpFlags;
854 if( pImpRec->nShapeId )
856 // Import-Record-Liste ergaenzen
857 pImpRec->pObj = pObj;
858 rImportData.aRecords.insert( pImpRec );
860 // Eintrag in Z-Order-Liste um Zeiger auf dieses Objekt ergaenzen
861 /*Only store objects which are not deep inside the tree*/
862 if( ( rObjData.nCalledByGroup == 0 )
864 ( (rObjData.nSpFlags & SP_FGROUP)
865 && (rObjData.nCalledByGroup < 2) )
867 StoreShapeOrder( pImpRec->nShapeId,
868 ( ( (sal_uLong)pImpRec->aTextId.nTxBxS ) << 16 )
869 + pImpRec->aTextId.nSequence, pObj );
871 else
872 delete pImpRec;
875 return pObj;
878 /***************************************************************************
879 # Spezial FastSave - Attribute
880 #**************************************************************************/
882 void SwWW8ImplReader::Read_StyleCode( sal_uInt16, const sal_uInt8* pData, short nLen )
884 if (nLen < 0)
886 bCpxStyle = false;
887 return;
889 sal_uInt16 nColl = 0;
890 if (pWwFib->GetFIBVersion() <= ww::eWW2)
891 nColl = *pData;
892 else
893 nColl = SVBT16ToShort(pData);
894 if (nColl < vColl.size())
896 SetTxtFmtCollAndListLevel( *pPaM, vColl[nColl] );
897 bCpxStyle = true;
901 // Read_Majority ist fuer Majority ( 103 ) und Majority50 ( 108 )
902 void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short )
906 //-----------------------------------------
907 // Stack
908 //-----------------------------------------
909 void SwWW8FltControlStack::NewAttr(const SwPosition& rPos,
910 const SfxPoolItem& rAttr)
912 OSL_ENSURE(RES_TXTATR_FIELD != rAttr.Which(), "probably don't want to put"
913 "fields into the control stack");
914 OSL_ENSURE(RES_FLTR_REDLINE != rAttr.Which(), "probably don't want to put"
915 "redlines into the control stack");
916 SwFltControlStack::NewAttr(rPos, rAttr);
919 SwFltStackEntry* SwWW8FltControlStack::SetAttr(const SwPosition& rPos, sal_uInt16 nAttrId,
920 sal_Bool bTstEnde, long nHand, sal_Bool )
922 SwFltStackEntry *pRet = NULL;
923 //Doing a textbox, and using the control stack only as a temporary
924 //collection point for properties which will are not to be set into
925 //the real document
926 if (rReader.pPlcxMan && rReader.pPlcxMan->GetDoingDrawTextBox())
928 size_t nCnt = size();
929 for (size_t i=0; i < nCnt; ++i)
931 SwFltStackEntry& rEntry = (*this)[i];
932 if (nAttrId == rEntry.pAttr->Which())
934 DeleteAndDestroy(i--);
935 --nCnt;
939 else //Normal case, set the attribute into the document
940 pRet = SwFltControlStack::SetAttr(rPos, nAttrId, bTstEnde, nHand);
941 return pRet;
944 long GetListFirstLineIndent(const SwNumFmt &rFmt)
946 OSL_ENSURE( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
947 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
949 SvxAdjust eAdj = rFmt.GetNumAdjust();
950 long nReverseListIndented;
951 if (eAdj == SVX_ADJUST_RIGHT)
952 nReverseListIndented = -rFmt.GetCharTextDistance();
953 else if (eAdj == SVX_ADJUST_CENTER)
954 nReverseListIndented = rFmt.GetFirstLineOffset()/2;
955 else
956 nReverseListIndented = rFmt.GetFirstLineOffset();
957 return nReverseListIndented;
960 static long lcl_GetTrueMargin(const SvxLRSpaceItem &rLR, const SwNumFmt &rFmt,
961 long &rFirstLinePos)
963 OSL_ENSURE( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
964 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
966 const long nBodyIndent = rLR.GetTxtLeft();
967 const long nFirstLineDiff = rLR.GetTxtFirstLineOfst();
968 rFirstLinePos = nBodyIndent + nFirstLineDiff;
970 const long nPseudoListBodyIndent = rFmt.GetAbsLSpace();
971 const long nReverseListIndented = GetListFirstLineIndent(rFmt);
972 long nExtraListIndent = nPseudoListBodyIndent + nReverseListIndented;
974 return nExtraListIndent > 0 ? nExtraListIndent : 0;
977 // #i103711#
978 // #i105414#
979 void SyncIndentWithList( SvxLRSpaceItem &rLR,
980 const SwNumFmt &rFmt,
981 const bool bFirstLineOfstSet,
982 const bool bLeftIndentSet )
984 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
986 long nWantedFirstLinePos;
987 long nExtraListIndent = lcl_GetTrueMargin(rLR, rFmt, nWantedFirstLinePos);
988 rLR.SetTxtLeft(nWantedFirstLinePos - nExtraListIndent);
989 rLR.SetTxtFirstLineOfst(0);
991 else if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
993 if ( !bFirstLineOfstSet && bLeftIndentSet &&
994 rFmt.GetFirstLineIndent() != 0 )
996 rLR.SetTxtFirstLineOfst( rFmt.GetFirstLineIndent() );
998 else if ( bFirstLineOfstSet && !bLeftIndentSet &&
999 rFmt.GetIndentAt() != 0 )
1001 rLR.SetTxtLeft( rFmt.GetIndentAt() );
1006 const SwNumFmt* SwWW8FltControlStack::GetNumFmtFromStack(const SwPosition &rPos,
1007 const SwTxtNode &rTxtNode)
1009 const SwNumFmt *pRet = 0;
1010 const SfxPoolItem *pItem = GetStackAttr(rPos, RES_FLTR_NUMRULE);
1011 if (pItem && rTxtNode.GetNumRule())
1013 String sName(((SfxStringItem*)pItem)->GetValue());
1014 if (rTxtNode.IsCountedInList())
1016 const SwNumRule *pRule = pDoc->FindNumRulePtr(sName);
1018 pRet = GetNumFmtFromSwNumRuleLevel(*pRule, rTxtNode.GetActualListLevel());
1021 return pRet;
1024 sal_Int32 SwWW8FltControlStack::GetCurrAttrCP() const
1026 return rReader.GetCurrAttrCP();
1029 bool SwWW8FltControlStack::IsParaEndInCPs(sal_Int32 nStart,sal_Int32 nEnd,bool bSdOD) const
1031 return rReader.IsParaEndInCPs(nStart,nEnd,bSdOD);
1034 //Clear the para end position recorded in reader intermittently for the least impact on loading performance
1035 void SwWW8FltControlStack::ClearParaEndPosition()
1037 if ( !empty() )
1038 return;
1040 rReader.ClearParaEndPosition();
1043 bool SwWW8FltControlStack::CheckSdOD(sal_Int32 nStart,sal_Int32 nEnd)
1045 return rReader.IsParaEndInCPs(nStart,nEnd);
1048 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos,
1049 SwFltStackEntry& rEntry)
1051 switch (rEntry.pAttr->Which())
1053 case RES_LR_SPACE:
1056 Loop over the affect nodes and
1057 a) convert the word style absolute indent to indent relative
1058 to any numbering indent active on the nodes
1059 b) adjust the writer style tabstops relative to the old
1060 paragraph indent to be relative to the new paragraph indent
1062 using namespace sw::util;
1063 SwPaM aRegion(rTmpPos);
1064 if (rEntry.MakeRegion(pDoc, aRegion, false))
1066 SvxLRSpaceItem aNewLR( *(SvxLRSpaceItem*)rEntry.pAttr );
1067 sal_uLong nStart = aRegion.Start()->nNode.GetIndex();
1068 sal_uLong nEnd = aRegion.End()->nNode.GetIndex();
1069 for(; nStart <= nEnd; ++nStart)
1071 SwNode* pNode = pDoc->GetNodes()[ nStart ];
1072 if (!pNode || !pNode->IsTxtNode())
1073 continue;
1075 SwCntntNode* pNd = (SwCntntNode*)pNode;
1076 SvxLRSpaceItem aOldLR = (const SvxLRSpaceItem&)
1077 pNd->GetAttr(RES_LR_SPACE);
1079 SwTxtNode *pTxtNode = (SwTxtNode*)pNode;
1081 const SwNumFmt *pNum = 0;
1082 pNum = GetNumFmtFromStack(*aRegion.GetPoint(),
1083 *pTxtNode);
1084 if (!pNum)
1086 pNum = GetNumFmtFromTxtNode(*pTxtNode);
1089 if ( pNum )
1091 // #i103711#
1092 const bool bFirstLineIndentSet =
1093 ( rReader.maTxtNodesHavingFirstLineOfstSet.end() !=
1094 rReader.maTxtNodesHavingFirstLineOfstSet.find( pNode ) );
1095 // #i105414#
1096 const bool bLeftIndentSet =
1097 ( rReader.maTxtNodesHavingLeftIndentSet.end() !=
1098 rReader.maTxtNodesHavingLeftIndentSet.find( pNode ) );
1099 SyncIndentWithList( aNewLR, *pNum,
1100 bFirstLineIndentSet,
1101 bLeftIndentSet );
1104 if (aNewLR == aOldLR)
1105 continue;
1107 pNd->SetAttr(aNewLR);
1112 break;
1113 case RES_TXTATR_FIELD:
1114 OSL_ENSURE(!this, "What is a field doing in the control stack,"
1115 "probably should have been in the endstack");
1116 break;
1117 case RES_TXTATR_INETFMT:
1119 SwPaM aRegion(rTmpPos);
1120 if (rEntry.MakeRegion(pDoc, aRegion, false))
1122 SwFrmFmt *pFrm;
1123 //If we have just one single inline graphic then
1124 //don't insert a field for the single frame, set
1125 //the frames hyperlink field attribute directly.
1126 if (0 != (pFrm = rReader.ContainsSingleInlineGraphic(aRegion)))
1128 const SwFmtINetFmt *pAttr = (const SwFmtINetFmt *)
1129 rEntry.pAttr;
1130 SwFmtURL aURL;
1131 aURL.SetURL(pAttr->GetValue(), false);
1132 aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1133 pFrm->SetFmtAttr(aURL);
1135 else
1137 pDoc->InsertPoolItem(aRegion, *rEntry.pAttr, 0);
1141 break;
1142 default:
1143 SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1144 break;
1148 const SfxPoolItem* SwWW8FltControlStack::GetFmtAttr(const SwPosition& rPos,
1149 sal_uInt16 nWhich)
1151 const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1152 if (!pItem)
1154 SwCntntNode const*const pNd = rPos.nNode.GetNode().GetCntntNode();
1155 if (!pNd)
1156 pItem = &pDoc->GetAttrPool().GetDefaultItem(nWhich);
1157 else
1160 If we're hunting for the indent on a paragraph and need to use the
1161 parent style indent, then return the indent in msword format, and
1162 not writer format, because that's the style that the filter works
1163 in (naturally)
1165 if (nWhich == RES_LR_SPACE)
1167 SfxItemState eState = SFX_ITEM_DEFAULT;
1168 if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1169 eState = pSet->GetItemState(RES_LR_SPACE, false);
1170 if (eState != SFX_ITEM_SET && rReader.nAktColl < rReader.vColl.size())
1171 pItem = &(rReader.vColl[rReader.nAktColl].maWordLR);
1175 If we're hunting for a character property, try and exact position
1176 within the text node for lookup
1178 if (pNd->IsTxtNode())
1180 xub_StrLen nPos = rPos.nContent.GetIndex();
1181 SfxItemSet aSet(pDoc->GetAttrPool(), nWhich, nWhich);
1182 if (static_cast<const SwTxtNode*>(pNd)->GetAttr(aSet, nPos, nPos))
1183 pItem = aSet.GetItem(nWhich);
1186 if (!pItem)
1187 pItem = &pNd->GetAttr(nWhich);
1190 return pItem;
1193 const SfxPoolItem* SwWW8FltControlStack::GetStackAttr(const SwPosition& rPos,
1194 sal_uInt16 nWhich)
1196 SwFltPosition aFltPos(rPos);
1198 size_t nSize = size();
1199 while (nSize)
1201 const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1202 if (rEntry.pAttr->Which() == nWhich)
1204 if ( (rEntry.bOpen) ||
1206 (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1207 (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1208 (rEntry.m_aMkPos.m_nCntnt <= aFltPos.m_nCntnt) &&
1209 (rEntry.m_aPtPos.m_nCntnt > aFltPos.m_nCntnt)
1213 * e.g. half-open range [0-3) so asking for properties at 3
1214 * means props that end at 3 are not included
1217 return rEntry.pAttr;
1221 return 0;
1224 bool SwWW8FltRefStack::IsFtnEdnBkmField(const SwFmtFld& rFmtFld, sal_uInt16& rBkmNo)
1226 const SwField* pFld = rFmtFld.GetFld();
1227 sal_uInt16 nSubType;
1228 if(pFld && (RES_GETREFFLD == pFld->Which())
1229 && ((REF_FOOTNOTE == (nSubType = pFld->GetSubType())) || (REF_ENDNOTE == nSubType))
1230 && !((SwGetRefField*)pFld)->GetSetRefName().isEmpty())
1232 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1233 IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark(
1234 ((SwGetRefField*)pFld)->GetSetRefName());
1235 if(ppBkmk != pMarkAccess->getMarksEnd())
1237 // find Sequence No of corresponding Foot-/Endnote
1238 rBkmNo = ppBkmk - pMarkAccess->getMarksBegin();
1239 return true;
1242 return false;
1245 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition& rTmpPos,
1246 SwFltStackEntry& rEntry)
1248 switch (rEntry.pAttr->Which())
1251 Look up these in our lists of bookmarks that were changed to
1252 variables, and replace the ref field with a var field, otherwise
1253 do normal (?) strange stuff
1255 case RES_TXTATR_FIELD:
1257 SwNodeIndex aIdx(rEntry.m_aMkPos.m_nNode, 1);
1258 SwPaM aPaM(aIdx, rEntry.m_aMkPos.m_nCntnt);
1260 SwFmtFld& rFmtFld = *(SwFmtFld*)rEntry.pAttr;
1261 SwField* pFld = rFmtFld.GetFld();
1263 // <NOT> got lost from revision 1.128 to 1.129
1264 if (!RefToVar(pFld, rEntry))
1266 sal_uInt16 nBkmNo;
1267 if( IsFtnEdnBkmField(rFmtFld, nBkmNo) )
1269 ::sw::mark::IMark const * const pMark = (pDoc->getIDocumentMarkAccess()->getMarksBegin() + nBkmNo)->get();
1271 const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1273 SwTxtNode* pTxt = rBkMrkPos.nNode.GetNode().GetTxtNode();
1274 if( pTxt && rBkMrkPos.nContent.GetIndex() )
1276 SwTxtAttr* const pFtn = pTxt->GetTxtAttrForCharAt(
1277 rBkMrkPos.nContent.GetIndex()-1, RES_TXTATR_FTN );
1278 if( pFtn )
1280 sal_uInt16 nRefNo = ((SwTxtFtn*)pFtn)->GetSeqRefNo();
1282 ((SwGetRefField*)pFld)->SetSeqNo( nRefNo );
1284 if( pFtn->GetFtn().IsEndNote() )
1285 ((SwGetRefField*)pFld)->SetSubType(REF_ENDNOTE);
1291 pDoc->InsertPoolItem(aPaM, *rEntry.pAttr, 0);
1292 MoveAttrs(*aPaM.GetPoint());
1294 break;
1295 case RES_FLTR_TOX:
1296 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1297 break;
1298 default:
1299 case RES_FLTR_BOOKMARK:
1300 OSL_ENSURE(!this, "EndStck used with non field, not what we want");
1301 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1302 break;
1307 For styles we will do our tabstop arithmetic in word style and adjust them to
1308 writer style after all the styles have been finished and the dust settles as
1309 to what affects what.
1311 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1312 word indexes and we'll turn them back into writer indexes when setting them
1313 into the document. If explicit left indent exist which affects them, then this
1314 is handled when the explicit left indent is set into the document
1316 void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1318 if (nLen < 0)
1320 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_PARATR_TABSTOP);
1321 return;
1324 sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1325 const sal_uInt8* pDel = pData + 1; // Del - Array
1327 sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1328 const sal_uInt8* pIns = pData + 2*nDel + 2; // Ins - Array
1330 short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1331 if (nRequiredLength > nLen)
1333 //would require more data than available to describe!, discard invalid
1334 //record
1335 nIns = 0;
1336 nDel = 0;
1339 WW8_TBD* pTyp = (WW8_TBD*)(pData + 2*nDel + 2*nIns + 2);// Typ - Array
1341 SvxTabStopItem aAttr(0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP);
1343 const SwTxtFmtColl* pSty = 0;
1344 sal_uInt16 nTabBase;
1345 if (pAktColl && nAktColl < vColl.size()) // StyleDef
1347 nTabBase = vColl[nAktColl].nBase;
1348 if (nTabBase < vColl.size()) // Based On
1349 pSty = (const SwTxtFmtColl*)vColl[nTabBase].pFmt;
1351 else
1352 { // Text
1353 nTabBase = nAktColl;
1354 if (nAktColl < vColl.size())
1355 pSty = (const SwTxtFmtColl*)vColl[nAktColl].pFmt;
1356 //TODO figure else here
1359 bool bFound = false;
1360 ::boost::unordered_set<size_t> aLoopWatch;
1361 while (pSty && !bFound)
1363 const SfxPoolItem* pTabs;
1364 bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1365 &pTabs) == SFX_ITEM_SET;
1366 if( bFound )
1367 aAttr = *((const SvxTabStopItem*)pTabs);
1368 else
1370 sal_uInt16 nOldTabBase = nTabBase;
1371 // If based on another
1372 if (nTabBase < vColl.size())
1373 nTabBase = vColl[nTabBase].nBase;
1375 if (
1376 nTabBase < vColl.size() &&
1377 nOldTabBase != nTabBase &&
1378 nTabBase != ww::stiNil
1381 // #i61789: Stop searching when next style is the same as the
1382 // current one (prevent loop)
1383 aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1384 if (nTabBase < vColl.size())
1385 pSty = (const SwTxtFmtColl*)vColl[nTabBase].pFmt;
1386 //TODO figure out the else branch
1388 if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1389 aLoopWatch.end())
1390 pSty = 0;
1392 else
1393 pSty = 0; // gib die Suche auf
1397 SvxTabStop aTabStop;
1398 for (short i=0; i < nDel; ++i)
1400 sal_uInt16 nPos = aAttr.GetPos(SVBT16ToShort(pDel + i*2));
1401 if( nPos != SVX_TAB_NOTFOUND )
1402 aAttr.Remove( nPos, 1 );
1405 for (short i=0; i < nIns; ++i)
1407 short nPos = SVBT16ToShort(pIns + i*2);
1408 aTabStop.GetTabPos() = nPos;
1409 switch( SVBT8ToByte( pTyp[i].aBits1 ) & 0x7 ) // pTyp[i].jc
1411 case 0:
1412 aTabStop.GetAdjustment() = SVX_TAB_ADJUST_LEFT;
1413 break;
1414 case 1:
1415 aTabStop.GetAdjustment() = SVX_TAB_ADJUST_CENTER;
1416 break;
1417 case 2:
1418 aTabStop.GetAdjustment() = SVX_TAB_ADJUST_RIGHT;
1419 break;
1420 case 3:
1421 aTabStop.GetAdjustment() = SVX_TAB_ADJUST_DECIMAL;
1422 break;
1423 case 4:
1424 continue; // ignoriere Bar
1427 switch( SVBT8ToByte( pTyp[i].aBits1 ) >> 3 & 0x7 )
1429 case 0:
1430 aTabStop.GetFill() = ' ';
1431 break;
1432 case 1:
1433 aTabStop.GetFill() = '.';
1434 break;
1435 case 2:
1436 aTabStop.GetFill() = '-';
1437 break;
1438 case 3:
1439 case 4:
1440 aTabStop.GetFill() = '_';
1441 break;
1444 sal_uInt16 nPos2 = aAttr.GetPos( nPos );
1445 if (nPos2 != SVX_TAB_NOTFOUND)
1446 aAttr.Remove(nPos2, 1); // sonst weigert sich das Insert()
1447 aAttr.Insert(aTabStop);
1450 if (nIns || nDel)
1451 NewAttr(aAttr);
1452 else
1454 //Here we have a tab definition which inserts no extra tabs, or deletes
1455 //no existing tabs. An older version of writer is probably the creater
1456 //of the document :-( . So if we are importing a style we can just
1457 //ignore it. But if we are importing into text we cannot as during
1458 //text SwWW8ImplReader::Read_Tab is called at the begin and end of
1459 //the range the attrib affects, and ignoring it would upset the
1460 //balance
1461 if (!pAktColl) //not importing into a style
1463 using namespace sw::util;
1464 SvxTabStopItem aOrig = pSty ?
1465 ItemGet<SvxTabStopItem>(*pSty, RES_PARATR_TABSTOP) :
1466 DefaultItemGet<SvxTabStopItem>(rDoc, RES_PARATR_TABSTOP);
1467 NewAttr(aOrig);
1472 //-----------------------------------------
1473 // DOP
1474 //-----------------------------------------
1476 void SwWW8ImplReader::ImportDop()
1478 // correct the LastPrinted date in DocumentProperties
1479 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1480 mpDocShell->GetModel(), uno::UNO_QUERY_THROW);
1481 uno::Reference<document::XDocumentProperties> xDocuProps(
1482 xDPS->getDocumentProperties());
1483 OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null");
1484 if (xDocuProps.is())
1486 DateTime aLastPrinted(
1487 msfilter::util::DTTM2DateTime(pWDop->dttmLastPrint));
1488 ::util::DateTime uDT(aLastPrinted.GetNanoSec(),
1489 aLastPrinted.GetSec(), aLastPrinted.GetMin(),
1490 aLastPrinted.GetHour(), aLastPrinted.GetDay(),
1491 aLastPrinted.GetMonth(), aLastPrinted.GetYear(), false);
1492 xDocuProps->setPrintDate(uDT);
1496 // COMPATIBILITY FLAGS START
1499 // i#78951, remember the unknown compatability options
1500 // so as to export them out
1501 rDoc.Setn32DummyCompatabilityOptions1( pWDop->GetCompatabilityOptions());
1502 rDoc.Setn32DummyCompatabilityOptions2( pWDop->GetCompatabilityOptions2());
1504 // Abstand zwischen zwei Absaetzen ist die SUMME von unterem
1505 // Abst. des ersten und oberem Abst. des zweiten
1506 rDoc.set(IDocumentSettingAccess::PARA_SPACE_MAX, pWDop->fDontUseHTMLAutoSpacing);
1507 rDoc.set(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES, true );
1508 // move tabs on alignment
1509 rDoc.set(IDocumentSettingAccess::TAB_COMPAT, true);
1510 // #i24363# tab stops relative to indent
1511 rDoc.set(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT, false);
1513 // Import Default-Tabs
1514 long nDefTabSiz = pWDop->dxaTab;
1515 if( nDefTabSiz < 56 )
1516 nDefTabSiz = 709;
1518 // wir wollen genau einen DefaultTab
1519 SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP );
1520 ((SvxTabStop&)aNewTab[0]).GetAdjustment() = SVX_TAB_ADJUST_DEFAULT;
1522 rDoc.GetAttrPool().SetPoolDefaultItem( aNewTab );
1524 // Import zoom factor.
1525 if (pWDop->wScaleSaved)
1527 uno::Sequence<beans::PropertyValue> aViewProps(3);
1528 aViewProps[0].Name = "ZoomFactor";
1529 aViewProps[0].Value <<= sal_Int16(pWDop->wScaleSaved);
1530 aViewProps[1].Name = "VisibleBottom";
1531 aViewProps[1].Value <<= sal_Int32(0);
1532 aViewProps[2].Name = "ZoomType";
1533 aViewProps[2].Value <<= sal_Int16(0);
1535 uno::Reference< uno::XComponentContext > xComponentContext(comphelper::getProcessComponentContext());
1536 uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(xComponentContext);
1537 xBox->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps));
1538 uno::Reference<container::XIndexAccess> xIndexAccess(xBox, uno::UNO_QUERY);
1539 uno::Reference<document::XViewDataSupplier> xViewDataSupplier(mpDocShell->GetModel(), uno::UNO_QUERY);
1540 xViewDataSupplier->setViewData(xIndexAccess);
1543 rDoc.set(IDocumentSettingAccess::USE_VIRTUAL_DEVICE, !pWDop->fUsePrinterMetrics);
1544 rDoc.set(IDocumentSettingAccess::USE_HIRES_VIRTUAL_DEVICE, true);
1545 rDoc.set(IDocumentSettingAccess::ADD_FLY_OFFSETS, true );
1546 rDoc.set(IDocumentSettingAccess::ADD_EXT_LEADING, !pWDop->fNoLeading);
1547 rDoc.set(IDocumentSettingAccess::OLD_NUMBERING, false);
1548 rDoc.set(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING, false); // #i47448#
1549 rDoc.set(IDocumentSettingAccess::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, !pWDop->fExpShRtn); // #i49277#, #i56856#
1550 rDoc.set(IDocumentSettingAccess::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT, false); // #i53199#
1551 rDoc.set(IDocumentSettingAccess::OLD_LINE_SPACING, false);
1553 // #i25901# - set new compatibility option
1554 // 'Add paragraph and table spacing at bottom of table cells'
1555 rDoc.set(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS, true);
1557 // #i11860# - set new compatibility option
1558 // 'Use former object positioning' to <sal_False>
1559 rDoc.set(IDocumentSettingAccess::USE_FORMER_OBJECT_POS, false);
1561 // #i27767# - set new compatibility option
1562 // 'Conder Wrapping mode when positioning object' to <sal_True>
1563 rDoc.set(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION, true);
1565 rDoc.set(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING, false); // #i13832#, #i24135#
1567 rDoc.set(IDocumentSettingAccess::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1569 rDoc.set(IDocumentSettingAccess::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, true); // #i3952#
1571 rDoc.set(IDocumentSettingAccess::INVERT_BORDER_SPACING, true);
1572 rDoc.set(IDocumentSettingAccess::COLLAPSE_EMPTY_CELL_PARA, true);
1573 rDoc.set(IDocumentSettingAccess::TAB_OVERFLOW, true);
1574 rDoc.set(IDocumentSettingAccess::UNBREAKABLE_NUMBERINGS, true);
1575 rDoc.set(IDocumentSettingAccess::CLIPPED_PICTURES, true);
1576 rDoc.set(IDocumentSettingAccess::TAB_OVER_MARGIN, true);
1579 // COMPATIBILITY FLAGS END
1582 //import magic doptypography information, if its there
1583 if (pWwFib->nFib > 105)
1584 ImportDopTypography(pWDop->doptypography);
1586 // disable form design mode to be able to use imported controls directly
1587 // #i31239# always disable form design mode, not only in protected docs
1589 using namespace com::sun::star;
1591 uno::Reference<lang::XComponent> xModelComp(mpDocShell->GetModel(),
1592 uno::UNO_QUERY);
1593 uno::Reference<beans::XPropertySet> xDocProps(xModelComp,
1594 uno::UNO_QUERY);
1595 if (xDocProps.is())
1597 uno::Reference<beans::XPropertySetInfo> xInfo =
1598 xDocProps->getPropertySetInfo();
1599 sal_Bool bValue = false;
1600 if (xInfo.is())
1602 if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1604 xDocProps->setPropertyValue("ApplyFormDesignMode", cppu::bool2any(bValue));
1610 mpDocShell->SetModifyPasswordHash(pWDop->lKeyProtDoc);
1612 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
1613 if (rOpt.IsUseEnhancedFields())
1614 rDoc.set(IDocumentSettingAccess::PROTECT_FORM, pWDop->fProtEnabled );
1617 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography &rTypo)
1619 using namespace com::sun::star;
1620 switch (rTypo.iLevelOfKinsoku)
1622 case 2: //custom
1624 i18n::ForbiddenCharacters aForbidden(rTypo.rgxchFPunct,
1625 rTypo.rgxchLPunct);
1626 rDoc.setForbiddenCharacters(rTypo.GetConvertedLang(),
1627 aForbidden);
1628 //Obviously cannot set the standard level 1 for japanese, so
1629 //bail out now while we can.
1630 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
1631 return;
1633 break;
1634 default:
1635 break;
1639 This MS hack means that level 2 of japanese is not in operation, so we put
1640 in what we know are the MS defaults, there is a complementary reverse
1641 hack in the writer. Its our default as well, but we can set it anyway
1642 as a flag for later.
1644 if (!rTypo.reserved2)
1646 i18n::ForbiddenCharacters aForbidden(rTypo.GetJapanNotBeginLevel1(),
1647 rTypo.GetJapanNotEndLevel1());
1648 rDoc.setForbiddenCharacters(LANGUAGE_JAPANESE,aForbidden);
1651 rDoc.set(IDocumentSettingAccess::KERN_ASIAN_PUNCTUATION, rTypo.fKerningPunct);
1652 rDoc.setCharacterCompressionType(static_cast<SwCharCompressType>(rTypo.iJustification));
1655 //-----------------------------------------
1656 // Fuss- und Endnoten
1658 //-----------------------------------------
1660 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader* pRdr ,WW8_CP nStartCp) :
1661 maTmpPos(*pRdr->pPaM->GetPoint()),
1662 mpOldStck(pRdr->pCtrlStck),
1663 mpOldAnchorStck(pRdr->pAnchorStck),
1664 mpOldRedlines(pRdr->mpRedlineStack),
1665 mpOldPlcxMan(pRdr->pPlcxMan),
1666 mpWFlyPara(pRdr->pWFlyPara),
1667 mpSFlyPara(pRdr->pSFlyPara),
1668 mpPreviousNumPaM(pRdr->pPreviousNumPaM),
1669 mpPrevNumRule(pRdr->pPrevNumRule),
1670 mpTableDesc(pRdr->pTableDesc),
1671 mnInTable(pRdr->nInTable),
1672 mnAktColl(pRdr->nAktColl),
1673 mcSymbol(pRdr->cSymbol),
1674 mbIgnoreText(pRdr->bIgnoreText),
1675 mbSymbol(pRdr->bSymbol),
1676 mbHdFtFtnEdn(pRdr->bHdFtFtnEdn),
1677 mbTxbxFlySection(pRdr->bTxbxFlySection),
1678 mbAnl(pRdr->bAnl),
1679 mbInHyperlink(pRdr->bInHyperlink),
1680 mbPgSecBreak(pRdr->bPgSecBreak),
1681 mbWasParaEnd(pRdr->bWasParaEnd),
1682 mbHasBorder(pRdr->bHasBorder),
1683 mbFirstPara(pRdr->bFirstPara)
1685 pRdr->bSymbol = false;
1686 pRdr->bHdFtFtnEdn = true;
1687 pRdr->bTxbxFlySection = pRdr->bAnl = pRdr->bPgSecBreak = pRdr->bWasParaEnd
1688 = pRdr->bHasBorder = false;
1689 pRdr->bFirstPara = true;
1690 pRdr->nInTable = 0;
1691 pRdr->pWFlyPara = 0;
1692 pRdr->pSFlyPara = 0;
1693 pRdr->pPreviousNumPaM = 0;
1694 pRdr->pPrevNumRule = 0;
1695 pRdr->pTableDesc = 0;
1696 pRdr->nAktColl = 0;
1699 pRdr->pCtrlStck = new SwWW8FltControlStack(&pRdr->rDoc, pRdr->nFieldFlags,
1700 *pRdr);
1702 pRdr->mpRedlineStack = new sw::util::RedlineStack(pRdr->rDoc);
1704 pRdr->pAnchorStck = new SwWW8FltAnchorStack(&pRdr->rDoc, pRdr->nFieldFlags);
1706 // rette die Attributverwaltung: dies ist noetig, da der neu anzulegende
1707 // PLCFx Manager natuerlich auf die gleichen FKPs zugreift, wie der alte
1708 // und deren Start-End-Positionen veraendert...
1709 if (pRdr->pPlcxMan)
1710 pRdr->pPlcxMan->SaveAllPLCFx(maPLCFxSave);
1712 if (nStartCp != -1)
1714 pRdr->pPlcxMan = new WW8PLCFMan(pRdr->pSBase,
1715 mpOldPlcxMan->GetManType(), nStartCp);
1718 maOldApos.push_back(false);
1719 maOldApos.swap(pRdr->maApos);
1720 maOldFieldStack.swap(pRdr->maFieldStack);
1723 void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
1725 pRdr->pWFlyPara = mpWFlyPara;
1726 pRdr->pSFlyPara = mpSFlyPara;
1727 pRdr->pPreviousNumPaM = mpPreviousNumPaM;
1728 pRdr->pPrevNumRule = mpPrevNumRule;
1729 pRdr->pTableDesc = mpTableDesc;
1730 pRdr->cSymbol = mcSymbol;
1731 pRdr->bSymbol = mbSymbol;
1732 pRdr->bIgnoreText = mbIgnoreText;
1733 pRdr->bHdFtFtnEdn = mbHdFtFtnEdn;
1734 pRdr->bTxbxFlySection = mbTxbxFlySection;
1735 pRdr->nInTable = mnInTable;
1736 pRdr->bAnl = mbAnl;
1737 pRdr->bInHyperlink = mbInHyperlink;
1738 pRdr->bWasParaEnd = mbWasParaEnd;
1739 pRdr->bPgSecBreak = mbPgSecBreak;
1740 pRdr->nAktColl = mnAktColl;
1741 pRdr->bHasBorder = mbHasBorder;
1742 pRdr->bFirstPara = mbFirstPara;
1744 // schliesse alle Attribute, da sonst Attribute
1745 // entstehen koennen, die aus dem Fly rausragen
1746 pRdr->DeleteCtrlStk();
1747 pRdr->pCtrlStck = mpOldStck;
1749 pRdr->mpRedlineStack->closeall(*pRdr->pPaM->GetPoint());
1750 delete pRdr->mpRedlineStack;
1751 pRdr->mpRedlineStack = mpOldRedlines;
1753 pRdr->DeleteAnchorStk();
1754 pRdr->pAnchorStck = mpOldAnchorStck;
1756 *pRdr->pPaM->GetPoint() = maTmpPos;
1758 if (mpOldPlcxMan != pRdr->pPlcxMan)
1760 delete pRdr->pPlcxMan;
1761 pRdr->pPlcxMan = mpOldPlcxMan;
1763 if (pRdr->pPlcxMan)
1764 pRdr->pPlcxMan->RestoreAllPLCFx(maPLCFxSave);
1765 pRdr->maApos.swap(maOldApos);
1766 pRdr->maFieldStack.swap(maOldFieldStack);
1769 void SwWW8ImplReader::Read_HdFtFtnText( const SwNodeIndex* pSttIdx,
1770 long nStartCp, long nLen, ManTypes nType )
1772 // rettet Flags u.ae. u. setzt sie zurueck
1773 WW8ReaderSave aSave( this );
1775 pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1; //
1776 pPaM->GetPoint()->nContent.Assign( pPaM->GetCntntNode(), 0 );
1778 // dann Text fuer Header, Footer o. Footnote einlesen
1780 ReadText( nStartCp, nLen, nType ); // Sepx dabei ignorieren
1781 aSave.Restore( this );
1784 //Use authornames, if not available fall back to initials.
1785 long SwWW8ImplReader::Read_And(WW8PLCFManResult* pRes)
1787 WW8PLCFx_SubDoc* pSD = pPlcxMan->GetAtn();
1788 if( !pSD )
1789 return 0;
1791 String sAuthor;
1792 String sInitials;
1793 if( bVer67 )
1795 const WW67_ATRD* pDescri = (const WW67_ATRD*)pSD->GetData();
1796 const String* pA = GetAnnotationAuthor(SVBT16ToShort(pDescri->ibst));
1797 if (pA)
1798 sAuthor = *pA;
1799 else
1800 sAuthor = String(pDescri->xstUsrInitl + 1, pDescri->xstUsrInitl[0],
1801 RTL_TEXTENCODING_MS_1252);
1803 else
1805 const WW8_ATRD* pDescri = (const WW8_ATRD*)pSD->GetData();
1808 sal_uInt16 nLen = SVBT16ToShort(pDescri->xstUsrInitl[0]);
1809 for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
1810 sInitials += SVBT16ToShort(pDescri->xstUsrInitl[nIdx]);
1813 if (const String* pA = GetAnnotationAuthor(SVBT16ToShort(pDescri->ibst)))
1814 sAuthor = *pA;
1815 else
1816 sAuthor = sInitials;
1818 // If there is a bookmark tag, a text range should be commented.
1819 sal_uInt32 nTagBkmk = SVBT32ToUInt32(pDescri->ITagBkmk);
1820 if (nTagBkmk != 0xFFFFFFFF)
1822 int nAtnIndex = GetAnnotationIndex(nTagBkmk);
1823 if (nAtnIndex != -1)
1825 WW8_CP nStart = GetAnnotationStart(nAtnIndex);
1826 WW8_CP nEnd = GetAnnotationEnd(nAtnIndex);
1827 sal_Int32 nLen = nEnd - nStart;
1828 if( nLen )
1830 if (pPaM->GetPoint()->nContent.GetIndex() >= nLen)
1832 pPaM->SetMark();
1833 pPaM->GetPoint()->nContent -= nLen;
1835 else if (pPaM->GetPoint()->nNode.GetNode().IsTxtNode() )
1837 pPaM->SetMark();
1838 nLen -= pPaM->GetPoint()->nContent.GetIndex();
1840 SwTxtNode* pTxtNode = 0;
1841 // Find first text node which affected by the comment
1842 while( pPaM->GetPoint()->nNode >= 0 )
1844 SwNode* pNode = 0;
1845 // Find previous text node
1848 pPaM->GetPoint()->nNode--;
1849 nLen--; // End line character
1850 pNode = &pPaM->GetPoint()->nNode.GetNode();
1852 while( !pNode->IsTxtNode() && pPaM->GetPoint()->nNode >= 0 );
1854 // Subtrackt previous text node's length
1855 if( pNode && pNode->IsTxtNode() )
1857 pTxtNode = pNode->GetTxtNode();
1858 if( nLen < pTxtNode->Len() )
1859 break;
1860 else
1861 nLen -= pTxtNode->Len();
1865 // Set postion of the text range's first character
1866 if( pTxtNode )
1868 pTxtNode->MakeStartIndex(&pPaM->GetPoint()->nContent);
1869 pPaM->GetPoint()->nContent += pTxtNode->Len() - nLen;
1877 sal_uInt32 nDateTime = 0;
1879 if (sal_uInt8 * pExtended = pPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
1881 sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; //Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
1882 if (pWwFib->lcbAtrdExtra/18 > nIndex)
1883 nDateTime = SVBT32ToUInt32(*(SVBT32*)(pExtended+(nIndex*18)));
1886 DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
1888 String sTxt;
1889 OutlinerParaObject *pOutliner = ImportAsOutliner( sTxt, pRes->nCp2OrIdx,
1890 pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
1892 this->pFmtOfJustInsertedApo = 0;
1893 SwPostItField aPostIt(
1894 (SwPostItFieldType*)rDoc.GetSysFldType(RES_POSTITFLD), sAuthor,
1895 sTxt, sInitials, String(), aDate );
1896 aPostIt.SetTextObject(pOutliner);
1898 // If this is a range, create the associated fieldmark.
1899 if (pPaM->HasMark())
1901 IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess();
1902 sw::mark::IFieldmark* pFieldmark = pMarksAccess->makeFieldBookmark(*pPaM, OUString(), ODF_COMMENTRANGE);
1903 aPostIt.SetName(pFieldmark->GetName());
1904 pPaM->Exchange();
1905 pPaM->DeleteMark();
1908 pCtrlStck->NewAttr(*pPaM->GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
1909 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aPostIt), 0);
1910 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_HIDDEN);
1912 return 0;
1915 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(long nStart, long nLen,
1916 SwFrmFmt &rHdFtFmt, sal_uInt16 nPageWidth)
1918 const SwNodeIndex* pSttIdx = rHdFtFmt.GetCntnt().GetCntntIdx();
1919 OSL_ENSURE(pSttIdx, "impossible");
1920 if (!pSttIdx)
1921 return;
1923 SwPosition aTmpPos(*pPaM->GetPoint());
1925 pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
1926 pPaM->GetPoint()->nContent.Assign(pPaM->GetCntntNode(), 0);
1928 SwFlyFrmFmt *pFrame = rDoc.MakeFlySection(FLY_AT_PARA, pPaM->GetPoint());
1930 SwFmtAnchor aAnch( pFrame->GetAnchor() );
1931 aAnch.SetType( FLY_AT_PARA );
1932 pFrame->SetFmtAttr( aAnch );
1933 SwFmtFrmSize aSz(ATT_MIN_SIZE, nPageWidth, MINLAY);
1934 SwFrmSize eFrmSize = ATT_MIN_SIZE;
1935 if( eFrmSize != aSz.GetWidthSizeType() )
1936 aSz.SetWidthSizeType( eFrmSize );
1937 pFrame->SetFmtAttr(aSz);
1938 pFrame->SetFmtAttr(SwFmtSurround(SURROUND_THROUGHT));
1939 pFrame->SetFmtAttr(SwFmtHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
1941 // #i43427# - send frame for header/footer into background.
1942 pFrame->SetFmtAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
1943 SdrObject* pFrmObj = CreateContactObject( pFrame );
1944 OSL_ENSURE( pFrmObj,
1945 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
1946 if ( pFrmObj )
1948 pFrmObj->SetOrdNum( 0L );
1950 MoveInsideFly(pFrame);
1952 const SwNodeIndex* pHackIdx = pFrame->GetCntnt().GetCntntIdx();
1954 Read_HdFtFtnText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
1956 MoveOutsideFly(pFrame, aTmpPos);
1959 void SwWW8ImplReader::Read_HdFtText(long nStart, long nLen, SwFrmFmt* pHdFtFmt)
1961 const SwNodeIndex* pSttIdx = pHdFtFmt->GetCntnt().GetCntntIdx();
1962 if (!pSttIdx)
1963 return;
1965 SwPosition aTmpPos( *pPaM->GetPoint() ); // merke alte Cursorposition
1967 Read_HdFtFtnText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
1969 *pPaM->GetPoint() = aTmpPos;
1973 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP) const
1975 //each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
1976 return (nHeaderCP < pWwFib->ccpHdr) ? true : false;
1979 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems, sal_uInt8 grpfIhdt,
1980 int nSect)
1982 if (pHdFt)
1984 WW8_CP start;
1985 long nLen;
1986 sal_uInt8 nNumber = 5;
1988 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
1990 if (nI & nWhichItems)
1992 bool bOk = true;
1993 if( bVer67 )
1994 bOk = ( pHdFt->GetTextPos(grpfIhdt, nI, start, nLen ) && nLen >= 2 );
1995 else
1997 pHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), start, nLen);
1998 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(start);
2001 if (bOk)
2002 return true;
2006 return false;
2009 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2010 const wwSection &rSection)
2012 sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2013 SwPageDesc *pPD = rSection.mpPage;
2015 if( pHdFt )
2017 WW8_CP start;
2018 long nLen;
2019 sal_uInt8 nNumber = 5;
2021 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2023 if (nI & grpfIhdt)
2025 bool bOk = true;
2026 if( bVer67 )
2027 bOk = ( pHdFt->GetTextPos(grpfIhdt, nI, start, nLen ) && nLen >= 2 );
2028 else
2030 pHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), start, nLen);
2031 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(start);
2034 bool bUseLeft
2035 = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) ? true: false;
2036 bool bUseFirst
2037 = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) ? true: false;
2038 bool bFooter
2039 = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) ? true: false;
2041 SwFrmFmt& rFmt = bUseLeft ? pPD->GetLeft()
2042 : bUseFirst ? pPD->GetFirstMaster()
2043 : pPD->GetMaster();
2045 SwFrmFmt* pHdFtFmt;
2046 // If we have empty first page header and footer.
2047 bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2048 if (bFooter)
2050 bIsFooter = true;
2051 //#i17196# Cannot have left without right
2052 if (!pPD->GetMaster().GetFooter().GetFooterFmt())
2053 pPD->GetMaster().SetFmtAttr(SwFmtFooter(true));
2054 if (bUseLeft)
2055 pPD->GetLeft().SetFmtAttr(SwFmtFooter(true));
2056 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2057 pPD->GetFirstMaster().SetFmtAttr(SwFmtFooter(true));
2058 pHdFtFmt = const_cast<SwFrmFmt*>(rFmt.GetFooter().GetFooterFmt());
2060 else
2062 bIsHeader = true;
2063 //#i17196# Cannot have left without right
2064 if (!pPD->GetMaster().GetHeader().GetHeaderFmt())
2065 pPD->GetMaster().SetFmtAttr(SwFmtHeader(true));
2066 if (bUseLeft)
2067 pPD->GetLeft().SetFmtAttr(SwFmtHeader(true));
2068 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2069 pPD->GetFirstMaster().SetFmtAttr(SwFmtHeader(true));
2070 pHdFtFmt = const_cast<SwFrmFmt*>(rFmt.GetHeader().GetHeaderFmt());
2073 if (bOk)
2075 bool bHackRequired = false;
2076 if (bIsHeader && rSection.IsFixedHeightHeader())
2077 bHackRequired = true;
2078 else if (bIsFooter && rSection.IsFixedHeightFooter())
2079 bHackRequired = true;
2081 if (bHackRequired)
2083 Read_HdFtTextAsHackedFrame(start, nLen, *pHdFtFmt,
2084 static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2086 else
2087 Read_HdFtText(start, nLen, pHdFtFmt);
2089 else if (!bOk && pPrev)
2090 CopyPageDescHdFt(pPrev, pPD, nI);
2092 bIsHeader = bIsFooter = false;
2098 bool wwSectionManager::SectionIsProtected(const wwSection &rSection) const
2100 return (mrReader.pWwFib->fReadOnlyRecommended && !rSection.IsNotProtected());
2103 void wwSectionManager::SetHdFt(wwSection &rSection, int nSect,
2104 const wwSection *pPrevious)
2106 // Header / Footer nicht da
2107 if (!rSection.maSep.grpfIhdt)
2108 return;
2110 OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2111 if (rSection.mpPage)
2113 mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : 0,
2114 rSection);
2117 // Kopf / Fuss - Index Updaten
2118 // Damit der Index auch spaeter noch stimmt
2119 if (mrReader.pHdFt)
2120 mrReader.pHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2124 class AttribHere : public std::unary_function<const xub_StrLen*, bool>
2126 private:
2127 xub_StrLen nPosition;
2128 public:
2129 AttribHere(xub_StrLen nPos) : nPosition(nPos) {}
2130 bool operator()(const xub_StrLen *pPosition) const
2132 return (*pPosition >= nPosition);
2136 void SwWW8ImplReader::AppendTxtNode(SwPosition& rPos)
2138 SwTxtNode* pTxt = pPaM->GetNode()->GetTxtNode();
2140 const SwNumRule* pRule = NULL;
2142 if (pTxt != NULL)
2143 pRule = sw::util::GetNumRuleFromTxtNode(*pTxt);
2145 if (
2146 pRule && !pWDop->fDontUseHTMLAutoSpacing &&
2147 (bParaAutoBefore || bParaAutoAfter)
2150 // If after spacing is set to auto, set the after space to 0
2151 if (bParaAutoAfter)
2152 SetLowerSpacing(*pPaM, 0);
2154 // If the previous textnode had numbering and
2155 // and before spacing is set to auto, set before space to 0
2156 if(pPrevNumRule && bParaAutoBefore)
2157 SetUpperSpacing(*pPaM, 0);
2159 // If the previous numbering rule was different we need
2160 // to insert a space after the previous paragraph
2161 if((pRule != pPrevNumRule) && pPreviousNumPaM)
2162 SetLowerSpacing(*pPreviousNumPaM, GetParagraphAutoSpace(pWDop->fDontUseHTMLAutoSpacing));
2164 // cache current paragraph
2165 if(pPreviousNumPaM)
2166 delete pPreviousNumPaM, pPreviousNumPaM = 0;
2168 pPreviousNumPaM = new SwPaM(*pPaM);
2169 pPrevNumRule = pRule;
2171 else if(!pRule && pPreviousNumPaM)
2173 // If the previous paragraph has numbering but the current one does not
2174 // we need to add a space after the previous paragraph
2175 SetLowerSpacing(*pPreviousNumPaM, GetParagraphAutoSpace(pWDop->fDontUseHTMLAutoSpacing));
2176 delete pPreviousNumPaM, pPreviousNumPaM = 0;
2177 pPrevNumRule = 0;
2179 else
2181 // clear paragraph cache
2182 if(pPreviousNumPaM)
2183 delete pPreviousNumPaM, pPreviousNumPaM = 0;
2184 pPrevNumRule = pRule;
2187 // If this is the first paragraph in the document and
2188 // Auto-spacing before paragraph is set,
2189 // set the upper spacing value to 0
2190 if(bParaAutoBefore && bFirstPara && !pWDop->fDontUseHTMLAutoSpacing)
2191 SetUpperSpacing(*pPaM, 0);
2193 bFirstPara = false;
2195 rDoc.AppendTxtNode(rPos);
2197 //We can flush all anchored graphics at the end of a paragraph.
2198 pAnchorStck->Flush();
2201 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2203 bool bRet = false;
2204 const SwPosition* pSpacingPos = rMyPam.GetPoint();
2206 const SvxULSpaceItem* pULSpaceItem = (const SvxULSpaceItem*)pCtrlStck->GetFmtAttr(*pSpacingPos, RES_UL_SPACE);
2208 if(pULSpaceItem != 0)
2210 SvxULSpaceItem aUL(*pULSpaceItem);
2212 if(bIsUpper)
2213 aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2214 else
2215 aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2217 xub_StrLen nEnd = pSpacingPos->nContent.GetIndex();
2218 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetCntntNode(), 0);
2219 pCtrlStck->NewAttr(*pSpacingPos, aUL);
2220 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetCntntNode(), nEnd);
2221 pCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2222 bRet = true;
2224 return bRet;
2227 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2229 return SetSpacing(rMyPam, nSpace, false);
2232 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2234 return SetSpacing(rMyPam, nSpace, true);
2237 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2239 if (bVer67)
2240 return 25;
2241 return nLevel ? 0x244C : 0x2417;
2244 void SwWW8ImplReader::EndSpecial()
2246 // Frame / Table / Anl
2247 if (bAnl)
2248 StopAllAnl(); // -> bAnl = false
2250 while(maApos.size() > 1)
2252 StopTable();
2253 maApos.pop_back();
2254 --nInTable;
2255 if (maApos[nInTable] == true)
2256 StopApo();
2259 if (maApos[0] == true)
2260 StopApo();
2262 OSL_ENSURE(!nInTable, "unclosed table!");
2265 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2267 // Frame / Table / Anl
2268 if (bInHyperlink)
2269 return false;
2271 rbReSync = false;
2273 OSL_ENSURE(nInTable >= 0,"nInTable < 0!");
2275 // TabRowEnd
2276 bool bTableRowEnd = (pPlcxMan->HasParaSprm(bVer67 ? 25 : 0x2417) != 0 );
2278 // es muss leider fuer jeden Absatz zuerst nachgesehen werden,
2279 // ob sich unter den sprms
2280 // das sprm 29 (bzw. 0x261B) befindet, das ein APO einleitet.
2281 // Alle weiteren sprms beziehen sich dann naemlich auf das APO und nicht
2282 // auf den normalen Text drumrum.
2283 // Dasselbe gilt fuer eine Tabelle ( sprm 24 (bzw. 0x2416) )
2284 // und Anls ( sprm 13 ).
2285 // WW: Tabelle in APO geht ( Beide Anfaende treten gleichzeitig auf )
2286 // WW: APO in Tabelle geht nicht
2287 // d.h. Wenn eine Tabelle Inhalt eines Apo ist, dann muss der
2288 // Apo-Anfang zuerst bearbeitet werden, damit die Tabelle im Apo steht
2289 // und nicht umgekehrt. Am Ende muss dagegen zuerst das Tabellenende
2290 // bearbeitet werden, da die Apo erst nach der Tabelle abgeschlossen
2291 // werden darf ( sonst wird das Apo-Ende nie gefunden ).
2292 // Dasselbe gilt fuer Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2294 // Wenn die Tabelle in einem Apo steht, fehlen im TabRowEnd-Bereich
2295 // die Apo-Angaben. Damit hier die Apo nicht beendet wird, wird
2296 // ProcessApo dann nicht aufgerufen.
2298 // KHZ: When there is a table inside the Apo the Apo-flags are also
2299 // missing for the 2nd, 3rd... paragraphs of each cell.
2302 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2303 // be considered, the sprm 6649 gives the level of the table
2304 sal_uInt8 nCellLevel = 0;
2306 if (bVer67)
2307 nCellLevel = 0 != pPlcxMan->HasParaSprm(24);
2308 else
2310 nCellLevel = 0 != pPlcxMan->HasParaSprm(0x2416);
2311 if (!nCellLevel)
2312 nCellLevel = 0 != pPlcxMan->HasParaSprm(0x244B);
2316 WW8_TablePos *pTabPos=0;
2317 WW8_TablePos aTabPos;
2318 if(nCellLevel && !bVer67)
2320 WW8PLCFxSave1 aSave;
2321 pPlcxMan->GetPap()->Save( aSave );
2322 rbReSync = true;
2323 WW8PLCFx_Cp_FKP* pPap = pPlcxMan->GetPapPLCF();
2324 WW8_CP nMyStartCp=nStartCp;
2326 if (const sal_uInt8 *pLevel = pPlcxMan->HasParaSprm(0x6649))
2327 nCellLevel = *pLevel;
2329 bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (nInTable<nCellLevel?nInTable:nCellLevel-1));
2331 //Bad Table, remain unchanged in level, e.g. #i19667#
2332 if (!bHasRowEnd)
2333 nCellLevel = static_cast< sal_uInt8 >(nInTable);
2335 if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2336 pTabPos = &aTabPos;
2338 pPlcxMan->GetPap()->Restore( aSave );
2341 // then look if we are in an Apo
2343 ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2345 //look to see if we are in a Table, but Table in foot/end note not allowed
2346 bool bStartTab = (nInTable < nCellLevel) && !bFtnEdn;
2348 bool bStopTab = bWasTabRowEnd && (nInTable > nCellLevel) && !bFtnEdn;
2350 bWasTabRowEnd = false; // must be deactivated right here to prevent next
2351 // WW8TabDesc::TableCellEnd() from making nonsense
2353 if (nInTable && !bTableRowEnd && !bStopTab && (nInTable == nCellLevel && aApo.HasStartStop()))
2354 bStopTab = bStartTab = true; // Required to stop and start table
2356 // Dann auf Anl (Nummerierung) testen
2357 // und dann alle Ereignisse in der richtigen Reihenfolge bearbeiten
2359 if( bAnl && !bTableRowEnd )
2361 const sal_uInt8* pSprm13 = pPlcxMan->HasParaSprm( 13 );
2362 if( pSprm13 )
2363 { // Noch Anl ?
2364 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2365 if( ( nT != WW8_Pause && nT != nWwNumType ) // Anl-Wechsel
2366 || aApo.HasStartStop() // erzwungenes Anl-Ende
2367 || bStopTab || bStartTab )
2369 StopAnlToRestart(nT); // Anl-Restart ( = Wechsel ) ueber sprms
2371 else
2373 NextAnlLine( pSprm13 ); // naechste Anl-Zeile
2376 else
2377 { // Anl normal zuende
2378 StopAllAnl(); // Wirkliches Ende
2381 if (bStopTab)
2383 StopTable();
2384 maApos.pop_back();
2385 --nInTable;
2387 if (aApo.mbStopApo)
2389 StopApo();
2390 maApos[nInTable] = false;
2393 if (aApo.mbStartApo)
2395 maApos[nInTable] = StartApo(aApo, pTabPos);
2396 // nach StartApo ist ein ReSync noetig ( eigentlich nur, falls die Apo
2397 // ueber eine FKP-Grenze geht
2398 rbReSync = true;
2400 if (bStartTab)
2402 WW8PLCFxSave1 aSave;
2403 pPlcxMan->GetPap()->Save( aSave );
2405 if (bAnl) // Nummerierung ueber Zellengrenzen
2406 StopAllAnl(); // fuehrt zu Absturz -> keine Anls
2407 // in Tabellen
2408 if(nInTable < nCellLevel)
2410 if (StartTable(nStartCp))
2411 ++nInTable;
2412 else
2413 break;
2414 maApos.push_back(false);
2416 if(nInTable >= nCellLevel)
2418 // nach StartTable ist ein ReSync noetig ( eigentlich nur, falls die
2419 // Tabelle ueber eine FKP-Grenze geht
2420 rbReSync = true;
2421 pPlcxMan->GetPap()->Restore( aSave );
2424 } while (!bFtnEdn && (nInTable < nCellLevel));
2425 return bTableRowEnd;
2428 CharSet SwWW8ImplReader::GetCurrentCharSet()
2431 #i2015
2432 If the hard charset is set use it, if not see if there is an open
2433 character run that has set the charset, if not then fallback to the
2434 current underlying paragraph style.
2436 CharSet eSrcCharSet = eHardCharSet;
2437 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2439 if (!maFontSrcCharSets.empty())
2440 eSrcCharSet = maFontSrcCharSets.top();
2441 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && nCharFmt >= 0 && (size_t)nCharFmt < vColl.size() )
2442 eSrcCharSet = vColl[nCharFmt].GetCharSet();
2443 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(nAktColl) && nAktColl < vColl.size())
2444 eSrcCharSet = vColl[nAktColl].GetCharSet();
2445 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2448 #i22206#/#i52786#
2449 The (default) character set used for a run of text is the default
2450 character set for the version of Word that last saved the document.
2452 This is a bit tentative, more might be required if the concept is correct.
2453 When later version of word write older 6/95 documents the charset is
2454 correctly set in the character runs involved, so its hard to reproduce
2455 documents that require this to be sure of the process involved.
2457 const SvxLanguageItem *pLang = (const SvxLanguageItem*)GetFmtAttr(RES_CHRATR_LANGUAGE);
2458 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2459 ::com::sun::star::lang::Locale aLocale(LanguageTag(eLang).getLocale());
2460 eSrcCharSet = msfilter::util::getBestTextEncodingFromLocale(aLocale);
2463 return eSrcCharSet;
2466 //Takashi Ono for CJK
2467 CharSet SwWW8ImplReader::GetCurrentCJKCharSet()
2470 #i2015
2471 If the hard charset is set use it, if not see if there is an open
2472 character run that has set the charset, if not then fallback to the
2473 current underlying paragraph style.
2475 CharSet eSrcCharSet = eHardCharSet;
2476 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2478 if (!maFontSrcCJKCharSets.empty())
2479 eSrcCharSet = maFontSrcCJKCharSets.top();
2480 if (!vColl.empty())
2482 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && nCharFmt >= 0 && (size_t)nCharFmt < vColl.size() )
2483 eSrcCharSet = vColl[nCharFmt].GetCJKCharSet();
2484 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && nAktColl < vColl.size())
2485 eSrcCharSet = vColl[nAktColl].GetCJKCharSet();
2487 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2488 { // patch from cmc for #i52786#
2490 #i22206#/#i52786#
2491 The (default) character set used for a run of text is the default
2492 character set for the version of Word that last saved the document.
2494 This is a bit tentative, more might be required if the concept is correct.
2495 When later version of word write older 6/95 documents the charset is
2496 correctly set in the character runs involved, so its hard to reproduce
2497 documents that require this to be sure of the process involved.
2499 const SvxLanguageItem *pLang =
2500 (const SvxLanguageItem*)GetFmtAttr(RES_CHRATR_LANGUAGE);
2501 if (pLang)
2503 switch (pLang->GetLanguage())
2505 case LANGUAGE_CZECH:
2506 eSrcCharSet = RTL_TEXTENCODING_MS_1250;
2507 break;
2508 default:
2509 eSrcCharSet = RTL_TEXTENCODING_MS_1252;
2510 break;
2515 return eSrcCharSet;
2518 void SwWW8ImplReader::PostProcessAttrs()
2520 if (mpPostProcessAttrsInfo != NULL)
2522 SfxItemIter aIter(mpPostProcessAttrsInfo->mItemSet);
2524 const SfxPoolItem * pItem = aIter.GetCurItem();
2525 if (pItem != NULL)
2529 pCtrlStck->NewAttr(*mpPostProcessAttrsInfo->mPaM.GetPoint(),
2530 *pItem);
2531 pCtrlStck->SetAttr(*mpPostProcessAttrsInfo->mPaM.GetMark(),
2532 pItem->Which(), true);
2534 while (!aIter.IsAtEnd() && 0 != (pItem = aIter.NextItem()));
2537 delete mpPostProcessAttrsInfo;
2538 mpPostProcessAttrsInfo = NULL;
2543 #i9241#
2544 It appears that some documents that are in a baltic 8 bit encoding which has
2545 some undefined characters can have use made of those characters, in which
2546 case they default to CP1252. If not then its perhaps that the font encoding
2547 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2548 is always 1252.
2550 So a encoding converter that on an undefined character attempts to
2551 convert from 1252 on the undefined character
2553 sal_Size Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2554 sal_Char *pIn, sal_Size nInLen, sal_Unicode *pOut, sal_Size nOutLen)
2556 const sal_uInt32 nFlags =
2557 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2558 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2559 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2560 RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2562 const sal_uInt32 nFlags2 =
2563 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2564 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2565 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2566 RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2568 sal_Size nDestChars=0;
2569 sal_Size nConverted=0;
2573 sal_uInt32 nInfo = 0;
2574 sal_Size nThisConverted=0;
2576 nDestChars += rtl_convertTextToUnicode(hConverter, 0,
2577 pIn+nConverted, nInLen-nConverted,
2578 pOut+nDestChars, nOutLen-nDestChars,
2579 nFlags, &nInfo, &nThisConverted);
2581 OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2583 nConverted += nThisConverted;
2585 if (
2586 nInfo & RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR ||
2587 nInfo & RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
2590 sal_Size nOtherConverted;
2591 rtl_TextToUnicodeConverter hCP1252Converter =
2592 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2593 nDestChars += rtl_convertTextToUnicode(hCP1252Converter, 0,
2594 pIn+nConverted, 1,
2595 pOut+nDestChars, nOutLen-nDestChars,
2596 nFlags2, &nInfo, &nOtherConverted);
2597 rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2598 nConverted+=1;
2600 } while (nConverted < nInLen);
2602 return nDestChars;
2605 bool SwWW8ImplReader::LangUsesHindiNumbers(sal_uInt16 nLang)
2607 bool bResult = false;
2609 switch (nLang)
2611 case 0x1401: // Arabic(Algeria)
2612 case 0x3c01: // Arabic(Bahrain)
2613 case 0xc01: // Arabic(Egypt)
2614 case 0x801: // Arabic(Iraq)
2615 case 0x2c01: // Arabic (Jordan)
2616 case 0x3401: // Arabic(Kuwait)
2617 case 0x3001: // Arabic(Lebanon)
2618 case 0x1001: // Arabic(Libya)
2619 case 0x1801: // Arabic(Morocco)
2620 case 0x2001: // Arabic(Oman)
2621 case 0x4001: // Arabic(Qatar)
2622 case 0x401: // Arabic(Saudi Arabia)
2623 case 0x2801: // Arabic(Syria)
2624 case 0x1c01: // Arabic(Tunisia)
2625 case 0x3801: // Arabic(U.A.E)
2626 case 0x2401: // Arabic(Yemen)
2627 bResult = true;
2628 break;
2629 default:
2630 break;
2633 return bResult;
2636 sal_Unicode SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar)
2638 if (nChar >= 0x0030 && nChar <= 0x0039)
2639 return nChar + 0x0630;
2641 return nChar;
2644 // Returnwert: true for no Sonderzeichen
2645 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, long nEnd, long nCpOfs)
2647 sal_Size nRequestedStrLen = nEnd - rPos;
2649 OSL_ENSURE(nRequestedStrLen, "String is 0");
2650 if (!nRequestedStrLen)
2651 return true;
2653 sal_Size nRequestedPos = pSBase->WW8Cp2Fc(nCpOfs+rPos, &bIsUnicode);
2654 bool bValidPos = checkSeek(*pStrm, nRequestedPos);
2655 OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
2656 if (!bValidPos)
2658 //Swallow missing range, e.g. #i95550#
2659 rPos+=nRequestedStrLen;
2660 return true;
2663 sal_Size nAvailableStrLen = pStrm->remainingSize() / (bIsUnicode ? 2 : 1);
2664 OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
2665 if (!nAvailableStrLen)
2667 //Swallow missing range, e.g. #i95550#
2668 rPos+=nRequestedStrLen;
2669 return true;
2672 sal_Size nValidStrLen = std::min(nRequestedStrLen, nAvailableStrLen);
2674 // Unicode-Flag neu setzen und notfalls File-Pos korrigieren
2675 // merke: Seek kostet nicht viel, da inline geprueft wird,
2676 // ob die korrekte FilePos nicht schon erreicht ist.
2677 xub_StrLen nStrLen;
2678 if (nValidStrLen <= (STRING_MAXLEN-1))
2679 nStrLen = writer_cast<xub_StrLen>(nValidStrLen);
2680 else
2681 nStrLen = STRING_MAXLEN-1;
2683 const CharSet eSrcCharSet = bVer67 ? GetCurrentCharSet() :
2684 RTL_TEXTENCODING_MS_1252;
2685 const CharSet eSrcCJKCharSet = bVer67 ? GetCurrentCJKCharSet() :
2686 RTL_TEXTENCODING_MS_1252;
2688 // allocate unicode string data
2689 rtl_uString *pStr = rtl_uString_alloc(nStrLen);
2690 sal_Unicode* pBuffer = pStr->buffer;
2691 sal_Unicode* pWork = pBuffer;
2693 sal_Char* p8Bits = NULL;
2695 rtl_TextToUnicodeConverter hConverter = 0;
2696 if (!bIsUnicode || bVer67)
2697 hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
2699 if (!bIsUnicode)
2700 p8Bits = new sal_Char[nStrLen];
2702 // read the stream data
2703 sal_uInt8 nBCode = 0;
2704 sal_uInt16 nUCode;
2705 xub_StrLen nL2;
2707 sal_uInt16 nCTLLang = 0;
2708 const SfxPoolItem * pItem = GetFmtAttr(RES_CHRATR_CTL_LANGUAGE);
2709 if (pItem != NULL)
2710 nCTLLang = dynamic_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
2712 for( nL2 = 0; nL2 < nStrLen; ++nL2, ++pWork )
2714 if (bIsUnicode)
2715 *pStrm >> nUCode; // unicode --> read 2 bytes
2716 else
2718 *pStrm >> nBCode; // old code --> read 1 byte
2719 nUCode = nBCode;
2722 if (pStrm->GetError())
2724 rPos = WW8_CP_MAX-10; // -> eof or other error
2725 rtl_freeMemory(pStr);
2726 delete [] p8Bits;
2727 return true;
2730 if ((32 > nUCode) || (0xa0 == nUCode))
2732 pStrm->SeekRel( bIsUnicode ? -2 : -1 );
2733 break; // Sonderzeichen < 32, == 0xa0 gefunden
2736 if (bIsUnicode)
2738 if (!bVer67)
2739 *pWork = nUCode;
2740 else
2742 if (nUCode >= 0x3000) //0x8000 ?
2744 sal_Char aTest[2];
2745 aTest[0] = static_cast< sal_Char >((nUCode & 0xFF00) >> 8);
2746 aTest[1] = static_cast< sal_Char >(nUCode & 0x00FF);
2747 String aTemp(aTest, 2, eSrcCJKCharSet);
2748 OSL_ENSURE(aTemp.Len() == 1, "so much for that theory");
2749 *pWork = aTemp.GetChar(0);
2751 else
2753 sal_Char cTest = static_cast< sal_Char >(nUCode & 0x00FF);
2754 Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
2758 else
2759 p8Bits[nL2] = nBCode;
2762 if (nL2)
2764 xub_StrLen nEndUsed = nL2;
2766 if (!bIsUnicode)
2767 nEndUsed = Custom8BitToUnicode(hConverter, p8Bits, nL2, pBuffer, nStrLen);
2769 for( xub_StrLen nI = 0; nI < nStrLen; ++nI, ++pBuffer )
2770 if (m_bRegardHindiDigits && bBidi && LangUsesHindiNumbers(nCTLLang))
2771 *pBuffer = TranslateToHindiNumbers(*pBuffer);
2773 pStr->buffer[nEndUsed] = 0;
2774 pStr->length = nEndUsed;
2776 emulateMSWordAddTextToParagraph(OUString(pStr, SAL_NO_ACQUIRE));
2777 pStr = NULL;
2778 rPos += nL2;
2779 if (!maApos.back()) //a para end in apo doesn't count
2780 bWasParaEnd = false; //kein CR
2783 if (hConverter)
2784 rtl_destroyTextToUnicodeConverter(hConverter);
2785 if (pStr)
2786 rtl_uString_release(pStr);
2787 delete [] p8Bits;
2788 return nL2 >= nStrLen;
2791 #define MSASCII SAL_MAX_INT16
2793 namespace
2795 //We want to force weak chars inside 0x0020 to 0x007F to LATIN
2796 sal_Int16 lcl_getScriptType(
2797 const uno::Reference<i18n::XBreakIterator>& rBI,
2798 const OUString &rString, sal_Int32 nPos)
2800 sal_Int16 nScript = rBI->getScriptType(rString, nPos);
2801 if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
2802 nScript = MSASCII;
2803 return nScript;
2806 //We want to know about WEAK segments, so endOfScript isn't
2807 //useful, and see lcl_getScriptType anyway
2808 sal_Int32 lcl_endOfScript(
2809 const uno::Reference<i18n::XBreakIterator>& rBI,
2810 const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
2812 while (nPos < rString.getLength())
2814 sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
2815 if (nScript != nNewScript)
2816 break;
2817 ++nPos;
2819 return nPos;
2822 sal_Int32 lcl_getWriterScriptType(
2823 const uno::Reference<i18n::XBreakIterator>& rBI,
2824 const OUString &rString, sal_Int32 nPos)
2826 sal_Int16 nScript = i18n::ScriptType::WEAK;
2828 if (rString.isEmpty())
2829 return nScript;
2831 while (nPos >= 0)
2833 nScript = rBI->getScriptType(rString, nPos);
2834 if (nScript != i18n::ScriptType::WEAK)
2835 break;
2836 --nPos;
2839 return nScript;
2842 bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
2844 return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
2847 bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
2849 //Ignoring CharSet, and ignoring unknown pitch
2850 return rA.GetFamilyName() == rB.GetFamilyName() &&
2851 rA.GetStyleName() == rB.GetStyleName() &&
2852 rA.GetFamily() == rB.GetFamily() &&
2853 samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
2857 //In writer we categorize text into CJK, CTL and "Western" for everything else.
2858 //Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
2859 //NonEastAsian/HighAnsi, with some shared characters and some properties to to
2860 //hint as to which way to bias those shared characters.
2862 //That's four categories, we however have three categories. Given that problem
2863 //here we would ideally find out "what would word do" to see what font/language
2864 //word would assign to characters based on the unicode range they fall into and
2865 //hack the word one onto the range we use. However it's unclear what word's
2866 //categorization is. So we don't do that here yet.
2868 //Additional to the categorization, when word encounters weak text for ambigious
2869 //chars it uses idcthint to indicate which way to bias. We don't have a idcthint
2870 //feature in writer.
2872 //So what we currently do here then is to split our text into non-weak/weak
2873 //sections and uses word's idcthint to determine what font it would use and
2874 //force that on for the segment. Following what we *do* know about word's
2875 //categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
2876 //word, something we map to LATIN, so we consider all weaks chars in that range
2877 //to auto-bias to LATIN.
2879 //See https://bugs.freedesktop.org/show_bug.cgi?id=34319 for an example
2880 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString& rAddString)
2882 if (rAddString.isEmpty())
2883 return;
2885 uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
2886 if (!xBI.is())
2888 simpleAddTextToParagraph(rAddString);
2889 return;
2892 sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
2893 sal_Int32 nLen = rAddString.getLength();
2895 OUString sParagraphText;
2896 const SwCntntNode *pCntNd = pPaM->GetCntntNode();
2897 const SwTxtNode* pNd = pCntNd ? pCntNd->GetTxtNode() : NULL;
2898 if (pNd)
2899 sParagraphText = pNd->GetTxt();
2900 sal_Int32 nParaOffset = sParagraphText.getLength();
2901 sParagraphText = sParagraphText + rAddString;
2903 sal_Int32 nPos = 0;
2904 while (nPos < nLen)
2906 sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
2907 if (nEnd < 0)
2908 break;
2910 OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
2911 const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
2912 const SvxFontItem *pOverriddenItems[] = {NULL, NULL, NULL};
2913 bool aForced[] = {false, false, false};
2915 int nLclIdctHint = 0xFF;
2916 if (nScript == i18n::ScriptType::WEAK)
2917 nLclIdctHint = nIdctHint;
2918 else if (nScript == MSASCII) //Force weak chars in ascii range to use LATIN font
2919 nLclIdctHint = 0;
2921 sal_uInt16 nForceFromFontId = 0;
2922 if (nLclIdctHint != 0xFF)
2924 switch (nLclIdctHint)
2926 case 0:
2927 nForceFromFontId = RES_CHRATR_FONT;
2928 break;
2929 case 1:
2930 nForceFromFontId = RES_CHRATR_CJK_FONT;
2931 break;
2932 case 2:
2933 nForceFromFontId = RES_CHRATR_CTL_FONT;
2934 break;
2935 default:
2936 break;
2940 if (nForceFromFontId != 0)
2942 //Now we know that word would use the nForceFromFontId font for this range
2943 //Try and determine what script writer would assign this range to
2945 sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
2946 nPos + nParaOffset);
2948 bool bWriterWillUseSameFontAsWordAutomatically = false;
2950 if (nWriterScript != i18n::ScriptType::WEAK)
2952 if (
2953 (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
2954 (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
2955 (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
2958 bWriterWillUseSameFontAsWordAutomatically = true;
2960 else
2962 const SvxFontItem *pSourceFont = (const SvxFontItem*)GetFmtAttr(nForceFromFontId);
2963 sal_uInt16 nDestId = aIds[nWriterScript-1];
2964 const SvxFontItem *pDestFont = (const SvxFontItem*)GetFmtAttr(nDestId);
2965 bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
2969 //Writer won't use the same font as word, so force the issue
2970 if (!bWriterWillUseSameFontAsWordAutomatically)
2972 const SvxFontItem *pSourceFont = (const SvxFontItem*)GetFmtAttr(nForceFromFontId);
2974 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
2976 const SvxFontItem *pDestFont = (const SvxFontItem*)GetFmtAttr(aIds[i]);
2977 aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
2978 if (aForced[i])
2980 pOverriddenItems[i] =
2981 (const SvxFontItem*)pCtrlStck->GetStackAttr(*pPaM->GetPoint(), aIds[i]);
2983 SvxFontItem aForceFont(*pSourceFont);
2984 aForceFont.SetWhich(aIds[i]);
2985 pCtrlStck->NewAttr(*pPaM->GetPoint(), aForceFont);
2991 simpleAddTextToParagraph(sChunk);
2993 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
2995 if (aForced[i])
2997 pCtrlStck->SetAttr(*pPaM->GetPoint(), aIds[i]);
2998 if (pOverriddenItems[i])
2999 pCtrlStck->NewAttr(*pPaM->GetPoint(), *(pOverriddenItems[i]));
3003 nPos = nEnd;
3004 if (nPos < nLen)
3005 nScript = lcl_getScriptType(xBI, rAddString, nPos);
3009 void SwWW8ImplReader::simpleAddTextToParagraph(const String& rAddString)
3011 if (!rAddString.Len())
3012 return;
3014 #if OSL_DEBUG_LEVEL > 1
3016 OString sText(OUStringToOString(rAddString, RTL_TEXTENCODING_UTF8));
3017 SAL_INFO("sw.ww8", "<addTextToParagraph>" << sText.getStr() << "</addTextToParagraph>");
3019 #endif
3021 const SwCntntNode *pCntNd = pPaM->GetCntntNode();
3022 const SwTxtNode* pNd = pCntNd ? pCntNd->GetTxtNode() : NULL;
3024 OSL_ENSURE(pNd, "What the hell, where's my text node");
3026 if (!pNd)
3027 return;
3029 if ((pNd->GetTxt().getLength() + rAddString.Len()) < STRING_MAXLEN-1)
3031 rDoc.InsertString(*pPaM, rAddString);
3033 else
3036 if (pNd->GetTxt().getLength() < STRING_MAXLEN -1)
3038 String sTempStr (rAddString,0,
3039 STRING_MAXLEN - pNd->GetTxt().getLength() -1);
3040 rDoc.InsertString(*pPaM, sTempStr);
3041 sTempStr = rAddString.Copy(sTempStr.Len(),
3042 rAddString.Len() - sTempStr.Len());
3043 AppendTxtNode(*pPaM->GetPoint());
3044 rDoc.InsertString(*pPaM, sTempStr);
3046 else
3048 AppendTxtNode(*pPaM->GetPoint());
3049 rDoc.InsertString(*pPaM, rAddString);
3053 bReadTable = false;
3056 // Returnwert: true for para end
3057 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, long nTextEnd,
3058 long nCpOfs)
3060 long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3062 if (bSymbol || bIgnoreText)
3064 if( bSymbol ) // Spezialzeichen einfuegen
3066 for(sal_uInt16 nCh = 0; nCh < nEnd - rPos; ++nCh)
3068 rDoc.InsertString( *pPaM, OUString(cSymbol) );
3070 pCtrlStck->SetAttr( *pPaM->GetPoint(), RES_CHRATR_FONT );
3072 pStrm->SeekRel( nEnd- rPos );
3073 rPos = nEnd; // ignoriere bis Attributende
3074 return false;
3077 while (true)
3079 if (ReadPlainChars(rPos, nEnd, nCpOfs))
3080 return false; // Fertig
3082 bool bStartLine = ReadChar(rPos, nCpOfs);
3083 rPos++;
3084 if (bPgSecBreak || bStartLine || rPos == nEnd) // CR oder Fertig
3086 return bStartLine;
3091 bool SwWW8ImplReader::HandlePageBreakChar()
3093 bool bParaEndAdded = false;
3094 //#i1909# section/page breaks should not occur in tables, word
3095 //itself ignores them in this case.
3096 if (!nInTable)
3098 //xushanchuan add for issue106569
3099 bool IsTemp=true;
3100 SwTxtNode* pTemp = pPaM->GetNode()->GetTxtNode();
3101 if (pTemp && pTemp->GetTxt().isEmpty()
3102 && (bFirstPara || bFirstParaOfPage))
3104 IsTemp = false;
3105 AppendTxtNode(*pPaM->GetPoint());
3106 pTemp->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE));
3108 //xushanchuan end
3109 bPgSecBreak = true;
3110 pCtrlStck->KillUnlockedAttrs(*pPaM->GetPoint());
3112 If its a 0x0c without a paragraph end before it, act like a
3113 paragraph end, but nevertheless, numbering (and perhaps other
3114 similar constructs) do not exist on the para.
3116 //xushanchuan add for issue106569
3117 if (!bWasParaEnd && IsTemp)
3118 //xushanchuan end
3120 bParaEndAdded = true;
3121 if (0 >= pPaM->GetPoint()->nContent.GetIndex())
3123 if (SwTxtNode* pTxtNode = pPaM->GetNode()->GetTxtNode())
3125 pTxtNode->SetAttr(
3126 *GetDfltAttr(RES_PARATR_NUMRULE));
3131 return bParaEndAdded;
3134 bool SwWW8ImplReader::ReadChar(long nPosCp, long nCpOfs)
3136 bool bNewParaEnd = false;
3137 // Unicode-Flag neu setzen und notfalls File-Pos korrigieren
3138 // merke: Seek kostet nicht viel, da inline geprueft wird,
3139 // ob die korrekte FilePos nicht schon erreicht ist.
3140 sal_Size nRequestedPos = pSBase->WW8Cp2Fc(nCpOfs+nPosCp, &bIsUnicode);
3141 if (!checkSeek(*pStrm, nRequestedPos))
3142 return false;
3144 sal_uInt8 nBCode(0);
3145 sal_uInt16 nWCharVal(0);
3146 if( bIsUnicode )
3147 *pStrm >> nWCharVal; // unicode --> read 2 bytes
3148 else
3150 *pStrm >> nBCode; // old code --> read 1 byte
3151 nWCharVal = nBCode;
3154 sal_Unicode cInsert = '\x0';
3155 bool bRet = false;
3156 //xushanchuan add for issue106569
3157 if ( 0xc != nWCharVal )
3158 bFirstParaOfPage = false;
3159 //xushanchuan end
3160 switch (nWCharVal)
3162 case 0:
3164 // Seitennummer
3165 SwPageNumberField aFld(
3166 (SwPageNumberFieldType*)rDoc.GetSysFldType(
3167 RES_PAGENUMBERFLD ), PG_RANDOM, SVX_NUM_ARABIC);
3168 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
3170 break;
3171 case 0xe:
3172 // if there is only one column word treats a column break like a pagebreak.
3173 if (maSectionManager.CurrentSectionColCount() < 2)
3174 bRet = HandlePageBreakChar();
3175 else if (!nInTable)
3177 // Always insert a txtnode for a column break, e.g. ##
3178 SwCntntNode *pCntNd=pPaM->GetCntntNode();
3179 if (pCntNd!=NULL && pCntNd->Len()>0) // if par is empty not break is needed
3180 AppendTxtNode(*pPaM->GetPoint());
3181 rDoc.InsertPoolItem(*pPaM, SvxFmtBreakItem(SVX_BREAK_COLUMN_BEFORE, RES_BREAK), 0);
3183 break;
3184 case 0x7:
3185 bNewParaEnd = true;
3186 TabCellEnd(); // table cell end (Flags abfragen!)
3187 break;
3188 case 0xf:
3189 if( !bSpec ) // "Satellit"
3190 cInsert = '\xa4';
3191 break;
3192 case 0x14:
3193 if( !bSpec ) // "Para-Ende"-Zeichen
3194 cInsert = '\xb5';
3195 break;
3196 case 0x15:
3197 if( !bSpec ) // Juristenparagraph
3198 cInsert = '\xa7';
3199 break;
3200 case 0x9:
3201 cInsert = '\x9'; // Tab
3202 break;
3203 case 0xb:
3204 cInsert = '\xa'; // Hard NewLine
3205 break;
3206 case 0xc:
3207 bRet = HandlePageBreakChar();
3208 break;
3209 case 0x1e: // Non-breaking hyphen
3210 rDoc.InsertString( *pPaM, OUString(CHAR_HARDHYPHEN) );
3211 break;
3212 case 0x1f: // Non-required hyphens
3213 rDoc.InsertString( *pPaM, OUString(CHAR_SOFTHYPHEN) );
3214 break;
3215 case 0xa0: // Non-breaking spaces
3216 rDoc.InsertString( *pPaM, OUString(CHAR_HARDBLANK) );
3217 break;
3218 case 0x1:
3220 Current thinking is that if bObj is set then we have a
3221 straightforward "traditional" ole object, otherwise we have a
3222 graphic preview of an associated ole2 object (or a simple
3223 graphic of course)
3225 //normally in the canvas field, the code is 0x8 0x1.
3226 //in a special case, the code is 0x1 0x1, which yields a simple picture
3228 bool bReadObj = IsInlineEscherHack();
3229 if( bReadObj )
3231 long nCurPos = pStrm->Tell();
3232 sal_uInt16 nWordCode(0);
3234 if( bIsUnicode )
3235 *pStrm >> nWordCode;
3236 else
3238 sal_uInt8 nByteCode(0);
3239 *pStrm >> nByteCode;
3240 nWordCode = nByteCode;
3242 if( nWordCode == 0x1 )
3243 bReadObj = false;
3244 pStrm->Seek( nCurPos );
3246 if( !bReadObj )
3248 SwFrmFmt *pResult = 0;
3249 if (bObj)
3250 pResult = ImportOle();
3251 else if (bSpec)
3252 pResult = ImportGraf();
3254 //#102160# If we have a bad 0x1 insert a space instead.
3255 if (!pResult)
3257 cInsert = ' ';
3258 OSL_ENSURE(!bObj && !bEmbeddObj && !nObjLocFc,
3259 "WW8: Please report this document, it may have a "
3260 "missing graphic");
3262 else
3264 // reset the flags.
3265 bObj = bEmbeddObj = false;
3266 nObjLocFc = 0;
3270 break;
3271 case 0x8:
3272 if( !bObj )
3273 Read_GrafLayer( nPosCp );
3274 break;
3275 case 0xd:
3276 bNewParaEnd = bRet = true;
3277 if (nInTable > 1)
3280 #i9666#/#i23161#
3281 Yes complex, if there is an entry in the undocumented PLCF
3282 which I believe to be a record of cell and row boundaries
3283 see if the magic bit which I believe to mean cell end is
3284 set. I also think btw that the third byte of the 4 byte
3285 value is the level of the cell
3287 WW8PLCFspecial* pTest = pPlcxMan->GetMagicTables();
3288 if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3289 pTest->Where() == nPosCp+1+nCpOfs)
3291 WW8_FC nPos;
3292 void *pData;
3293 pTest->Get(nPos, pData);
3294 sal_uInt32 nData = SVBT32ToUInt32(*(SVBT32*)pData);
3295 if (nData & 0x2) //Might be how it works
3297 TabCellEnd();
3298 bRet = false;
3301 else if (bWasTabCellEnd)
3303 TabCellEnd();
3304 bRet = false;
3308 bWasTabCellEnd = false;
3310 break; // line end
3311 case 0x5: // Annotation reference
3312 case 0x13:
3313 break;
3314 case 0x2: // Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Ftn later
3315 if (!maFtnStack.empty())
3316 cInsert = 0x2;
3317 break;
3318 default:
3319 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3320 break;
3323 if( '\x0' != cInsert )
3325 OUString sInsert(cInsert);
3326 emulateMSWordAddTextToParagraph(sInsert);
3328 if (!maApos.back()) //a para end in apo doesn't count
3329 bWasParaEnd = bNewParaEnd;
3330 return bRet;
3333 void SwWW8ImplReader::ProcessAktCollChange(WW8PLCFManResult& rRes,
3334 bool* pStartAttr, bool bCallProcessSpecial)
3336 sal_uInt16 nOldColl = nAktColl;
3337 nAktColl = pPlcxMan->GetColl();
3339 // Invalid Style-Id
3340 if (nAktColl >= vColl.size() || !vColl[nAktColl].pFmt || !vColl[nAktColl].bColl)
3342 nAktColl = 0;
3343 bParaAutoBefore = false;
3344 bParaAutoAfter = false;
3346 else
3348 bParaAutoBefore = vColl[nAktColl].bParaAutoBefore;
3349 bParaAutoAfter = vColl[nAktColl].bParaAutoAfter;
3352 if (nOldColl >= vColl.size())
3353 nOldColl = 0; //guess! TODO make sure this is what we want
3355 bool bTabRowEnd = false;
3356 if( pStartAttr && bCallProcessSpecial && !bInHyperlink )
3358 bool bReSync;
3359 // Frame / Table / Autonumbering List Level
3360 bTabRowEnd = ProcessSpecial(bReSync, rRes.nAktCp+pPlcxMan->GetCpOfs());
3361 if( bReSync )
3362 *pStartAttr = pPlcxMan->Get( &rRes ); // hole Attribut-Pos neu
3365 if (!bTabRowEnd && StyleExists(nAktColl))
3367 SetTxtFmtCollAndListLevel( *pPaM, vColl[ nAktColl ]);
3368 ChkToggleAttr(vColl[ nOldColl ].n81Flags, vColl[ nAktColl ].n81Flags);
3369 ChkToggleBiDiAttr(vColl[nOldColl].n81BiDiFlags,
3370 vColl[nAktColl].n81BiDiFlags);
3374 long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTxtPos, bool& rbStartLine)
3376 long nSkipChars = 0;
3377 WW8PLCFManResult aRes;
3379 OSL_ENSURE(pPaM->GetNode()->GetTxtNode(), "Missing txtnode");
3380 bool bStartAttr = pPlcxMan->Get(&aRes); // hole Attribut-Pos
3381 aRes.nAktCp = rTxtPos; // Akt. Cp-Pos
3383 bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !bIgnoreText;
3384 if ( bNewSection ) // neue Section
3386 OSL_ENSURE(pPaM->GetNode()->GetTxtNode(), "Missing txtnode");
3387 // PageDesc erzeugen und fuellen
3388 maSectionManager.CreateSep(rTxtPos, bPgSecBreak);
3389 // -> 0xc war ein Sectionbreak, aber
3390 // kein Pagebreak;
3391 bPgSecBreak = false; // PageDesc erzeugen und fuellen
3392 OSL_ENSURE(pPaM->GetNode()->GetTxtNode(), "Missing txtnode");
3395 // neuer Absatz ueber Plcx.Fkp.papx
3396 if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3398 ProcessAktCollChange( aRes, &bStartAttr,
3399 MAN_MASK_NEW_PAP == (aRes.nFlags & MAN_MASK_NEW_PAP) &&
3400 !bIgnoreText );
3401 rbStartLine = false;
3404 // position of last CP that's to be ignored
3405 long nSkipPos = -1;
3407 if( 0 < aRes.nSprmId ) // leere Attrs ignorieren
3409 if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3411 if( bStartAttr ) // WW-Attribute
3413 if( aRes.nMemLen >= 0 )
3414 ImportSprm(aRes.pMemPos, aRes.nSprmId);
3416 else
3417 EndSprm( aRes.nSprmId ); // Attr ausschalten
3419 else if( aRes.nSprmId < 0x800 ) // eigene Hilfs-Attribute
3421 if (bStartAttr)
3423 nSkipChars = ImportExtSprm(&aRes);
3424 if (
3425 (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3426 (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3429 // Felder/Ftn-/End-Note hier ueberlesen
3430 rTxtPos += nSkipChars;
3431 nSkipPos = rTxtPos-1;
3434 else
3435 EndExtSprm( aRes.nSprmId );
3439 pStrm->Seek(pSBase->WW8Cp2Fc( pPlcxMan->GetCpOfs() + rTxtPos, &bIsUnicode));
3441 // Find next Attr position (and Skip attributes of field contents if needed)
3442 if (nSkipChars && !bIgnoreText)
3443 pCtrlStck->MarkAllAttrsOld();
3444 bool bOldIgnoreText = bIgnoreText;
3445 bIgnoreText = true;
3446 sal_uInt16 nOldColl = nAktColl;
3447 bool bDoPlcxManPlusPLus = true;
3448 long nNext;
3451 if( bDoPlcxManPlusPLus )
3452 pPlcxMan->advance();
3453 nNext = pPlcxMan->Where();
3455 if (mpPostProcessAttrsInfo &&
3456 mpPostProcessAttrsInfo->mnCpStart == nNext)
3458 mpPostProcessAttrsInfo->mbCopy = true;
3461 if( (0 <= nNext) && (nSkipPos >= nNext) )
3463 nNext = ReadTextAttr( rTxtPos, rbStartLine );
3464 bDoPlcxManPlusPLus = false;
3465 bIgnoreText = true;
3468 if (mpPostProcessAttrsInfo &&
3469 nNext > mpPostProcessAttrsInfo->mnCpEnd)
3471 mpPostProcessAttrsInfo->mbCopy = false;
3474 while( nSkipPos >= nNext );
3475 bIgnoreText = bOldIgnoreText;
3476 if( nSkipChars )
3478 pCtrlStck->KillUnlockedAttrs( *pPaM->GetPoint() );
3479 if( nOldColl != pPlcxMan->GetColl() )
3480 ProcessAktCollChange(aRes, 0, false);
3483 return nNext;
3486 //Revised 2012.8.16 for the complex attribute presentation of 0x0D in MS
3487 bool SwWW8ImplReader::IsParaEndInCPs(sal_Int32 nStart, sal_Int32 nEnd,bool bSdOD) const
3489 //Revised for performance consideration
3490 if (nStart == -1 || nEnd == -1 || nEnd < nStart )
3491 return false;
3493 for (cp_vector::const_reverse_iterator aItr = maEndParaPos.rbegin(); aItr!= maEndParaPos.rend(); ++aItr)
3495 //Revised 2012.8.16,to the 0x0D,the attribute will have two situations
3496 //*********within***********exact******//
3497 //*********but also sample with only left and the position of 0x0d is the edge of the right side***********//
3498 if ( bSdOD && ( (nStart < *aItr && nEnd > *aItr) || ( nStart == nEnd && *aItr == nStart)) )
3499 return true;
3500 else if ( !bSdOD && (nStart < *aItr && nEnd >= *aItr) )
3501 return true;
3504 return false;
3507 //Clear the para end position recorded in reader intermittently for the least impact on loading performance
3508 void SwWW8ImplReader::ClearParaEndPosition()
3510 if ( maEndParaPos.size() > 0 )
3511 maEndParaPos.clear();
3514 void SwWW8ImplReader::ReadAttrs(WW8_CP& rNext, WW8_CP& rTxtPos, bool& rbStartLine)
3516 if( rTxtPos >= rNext )
3517 { // Stehen Attribute an ?
3521 maCurrAttrCP = rTxtPos;
3522 rNext = ReadTextAttr( rTxtPos, rbStartLine );
3524 while( rTxtPos >= rNext );
3527 else if ( rbStartLine )
3529 // keine Attribute, aber trotzdem neue Zeile
3530 // wenn eine Zeile mit einem Seitenumbruch aufhoert und sich keine
3531 // Absatzattribute / Absatzvorlagen aendern, ist das Zeilenende
3532 // nicht im Plcx.Fkp.papx eingetragen, d.h. ( nFlags & MAN_MASK_NEW_PAP )
3533 // ist false. Deshalb muss als Sonderbehandlung hier die Vorlage gesetzt
3534 // werden.
3535 if (!bCpxStyle && nAktColl < vColl.size())
3536 SetTxtFmtCollAndListLevel(*pPaM, vColl[nAktColl]);
3537 rbStartLine = false;
3541 // CloseAttrEnds zum Lesen nur der Attributenden am Ende eines Textes oder
3542 // Textbereiches ( Kopfzeile, Fussnote, ...). Attributanfaenge, Felder
3543 // werden ignoriert.
3544 void SwWW8ImplReader::CloseAttrEnds()
3546 //If there are any unclosed sprms then copy them to
3547 //another stack and close the ones that must be closed
3548 std::stack<sal_uInt16> aStack;
3549 pPlcxMan->TransferOpenSprms(aStack);
3551 while (!aStack.empty())
3553 sal_uInt16 nSprmId = aStack.top();
3554 if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
3555 EndSprm(nSprmId);
3556 aStack.pop();
3559 EndSpecial();
3562 bool SwWW8ImplReader::ReadText(long nStartCp, long nTextLen, ManTypes nType)
3564 bool bJoined=false;
3566 bool bStartLine = true;
3567 short nCrCount = 0;
3568 short nDistance = 0;
3570 bWasParaEnd = false;
3571 nAktColl = 0;
3572 pAktItemSet = 0;
3573 nCharFmt = -1;
3574 bSpec = false;
3575 bPgSecBreak = false;
3577 pPlcxMan = new WW8PLCFMan( pSBase, nType, nStartCp );
3578 long nCpOfs = pPlcxMan->GetCpOfs(); // Offset fuer Header/Footer, Footnote
3580 WW8_CP nNext = pPlcxMan->Where();
3581 SwTxtNode* pPreviousNode = 0;
3582 sal_uInt8 nDropLines = 0;
3583 SwCharFmt* pNewSwCharFmt = 0;
3584 const SwCharFmt* pFmt = 0;
3585 pStrm->Seek( pSBase->WW8Cp2Fc( nStartCp + nCpOfs, &bIsUnicode ) );
3587 WW8_CP l = nStartCp;
3588 while ( l<nStartCp+nTextLen )
3590 ReadAttrs( nNext, l, bStartLine );// behandelt auch Section-Breaks
3591 OSL_ENSURE(pPaM->GetNode()->GetTxtNode(), "Missing txtnode");
3593 if (mpPostProcessAttrsInfo != NULL)
3594 PostProcessAttrs();
3596 if( l>= nStartCp + nTextLen )
3597 break;
3599 bStartLine = ReadChars(l, nNext, nStartCp+nTextLen, nCpOfs);
3601 // If the previous paragraph was a dropcap then do not
3602 // create a new txtnode and join the two paragraphs together
3604 if (bStartLine && !pPreviousNode) // Zeilenende
3606 //We will record the CP of a paragraph end ('0x0D'), if current loading contents is from main stream;
3607 if (mbOnLoadingMain)
3608 maEndParaPos.push_back(l-1);
3609 AppendTxtNode(*pPaM->GetPoint());
3612 if (pPreviousNode && bStartLine)
3614 SwTxtNode* pEndNd = pPaM->GetNode()->GetTxtNode();
3615 const xub_StrLen nDropCapLen = pPreviousNode->GetTxt().getLength();
3617 // Need to reset the font size and text position for the dropcap
3619 SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
3620 pCtrlStck->Delete(aTmp);
3623 // Get the default document dropcap which we can use as our template
3624 const SwFmtDrop* defaultDrop =
3625 (const SwFmtDrop*) GetFmtAttr(RES_PARATR_DROP);
3626 SwFmtDrop aDrop(*defaultDrop);
3628 aDrop.GetLines() = nDropLines;
3629 aDrop.GetDistance() = nDistance;
3630 aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
3631 // Word has no concept of a "whole word dropcap"
3632 aDrop.GetWholeWord() = false;
3634 if (pFmt)
3635 aDrop.SetCharFmt(const_cast<SwCharFmt*>(pFmt));
3636 else if(pNewSwCharFmt)
3637 aDrop.SetCharFmt(const_cast<SwCharFmt*>(pNewSwCharFmt));
3639 SwPosition aStart(*pEndNd);
3640 pCtrlStck->NewAttr(aStart, aDrop);
3641 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_PARATR_DROP);
3642 pPreviousNode = 0;
3644 else if (bDropCap)
3646 // If we have found a dropcap store the textnode
3647 pPreviousNode = pPaM->GetNode()->GetTxtNode();
3649 const sal_uInt8 *pDCS;
3651 if (bVer67)
3652 pDCS = pPlcxMan->GetPapPLCF()->HasSprm(46);
3653 else
3654 pDCS = pPlcxMan->GetPapPLCF()->HasSprm(0x442C);
3656 if (pDCS)
3657 nDropLines = (*pDCS) >> 3;
3658 else // There is no Drop Cap Specifier hence no dropcap
3659 pPreviousNode = 0;
3661 if (const sal_uInt8 *pDistance = pPlcxMan->GetPapPLCF()->HasSprm(0x842F))
3662 nDistance = SVBT16ToShort( pDistance );
3663 else
3664 nDistance = 0;
3666 const SwFmtCharFmt *pSwFmtCharFmt = 0;
3668 if(pAktItemSet)
3669 pSwFmtCharFmt = &(ItemGet<SwFmtCharFmt>(*pAktItemSet, RES_TXTATR_CHARFMT));
3671 if(pSwFmtCharFmt)
3672 pFmt = pSwFmtCharFmt->GetCharFmt();
3674 if(pAktItemSet && !pFmt)
3676 OUString sPrefix(OUStringBuffer("WW8Dropcap").append(nDropCap++).makeStringAndClear());
3677 pNewSwCharFmt = rDoc.MakeCharFmt(sPrefix, (SwCharFmt*)rDoc.GetDfltCharFmt());
3678 pAktItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
3679 pNewSwCharFmt->SetFmtAttr( *pAktItemSet );
3682 delete pAktItemSet;
3683 pAktItemSet = 0;
3684 bDropCap=false;
3687 if (bStartLine || bWasTabRowEnd)
3689 // alle 64 CRs aufrufen not for Header u. ae.
3690 if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT)
3692 nProgress = (sal_uInt16)( l * 100 / nTextLen );
3693 ::SetProgressState(nProgress, mpDocShell); // Update
3697 // If we have encountered a 0x0c which indicates either section of
3698 // pagebreak then look it up to see if it is a section break, and
3699 // if it is not then insert a page break. If it is a section break
3700 // it will be handled as such in the ReadAttrs of the next loop
3701 if (bPgSecBreak)
3703 // We need only to see if a section is ending at this cp,
3704 // the plcf will already be sitting on the correct location
3705 // if it is there.
3706 WW8PLCFxDesc aTemp;
3707 aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
3708 if (pPlcxMan->GetSepPLCF())
3709 pPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
3710 if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
3712 // #i39251# - insert text node for page break, if no one inserted.
3713 // #i43118# - refine condition: the anchor
3714 // control stack has to have entries, otherwise it's not needed
3715 // to insert a text node.
3716 if (!bStartLine && !pAnchorStck->empty())
3718 AppendTxtNode(*pPaM->GetPoint());
3720 rDoc.InsertPoolItem(*pPaM,
3721 SvxFmtBreakItem(SVX_BREAK_PAGE_BEFORE, RES_BREAK), 0);
3722 bFirstParaOfPage = true;//xushanchuan add for issue106569
3723 bPgSecBreak = false;
3728 if (pPaM->GetPoint()->nContent.GetIndex())
3729 AppendTxtNode(*pPaM->GetPoint());
3731 if (!bInHyperlink)
3732 bJoined = JoinNode(*pPaM);
3734 CloseAttrEnds();
3736 delete pPlcxMan, pPlcxMan = 0;
3737 return bJoined;
3740 /***************************************************************************
3741 # class SwWW8ImplReader
3742 #**************************************************************************/
3744 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara, SvStorage* pStorage,
3745 SvStream* pSt, SwDoc& rD, const String& rBaseURL, bool bNewDoc) :
3746 mpDocShell(rD.GetDocShell()),
3747 pStg(pStorage),
3748 pStrm(pSt),
3749 pTableStream(0),
3750 pDataStream(0),
3751 rDoc(rD),
3752 maSectionManager(*this),
3753 m_aExtraneousParas(rD),
3754 maInsertedTables(rD),
3755 maSectionNameGenerator(rD, OUString("WW")),
3756 maGrfNameGenerator(bNewDoc, OUString('G')),
3757 maParaStyleMapper(rD),
3758 maCharStyleMapper(rD),
3759 maTxtNodesHavingFirstLineOfstSet(), // #i103711#
3760 maTxtNodesHavingLeftIndentSet(), // #i105414#
3761 pMSDffManager(0),
3762 mpAtnNames(0),
3763 sBaseURL(rBaseURL),
3764 m_bRegardHindiDigits( false ),
3765 mbNewDoc(bNewDoc),
3766 nDropCap(0),
3767 nIdctHint(0),
3768 bBidi(false),
3769 bReadTable(false),
3770 maCurrAttrCP(-1),
3771 mbOnLoadingMain(false)
3773 pStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
3774 nWantedVersion = nVersionPara;
3775 pCtrlStck = 0;
3776 mpRedlineStack = 0;
3777 pReffedStck = 0;
3778 pReffingStck = 0;
3779 pAnchorStck = 0;
3780 pFonts = 0;
3781 pSBase = 0;
3782 pPlcxMan = 0;
3783 pStyles = 0;
3784 pAktColl = 0;
3785 pLstManager = 0;
3786 pAktItemSet = 0;
3787 pDfltTxtFmtColl = 0;
3788 pStandardFmtColl = 0;
3789 pHdFt = 0;
3790 pWFlyPara = 0;
3791 pSFlyPara = 0;
3792 pFlyFmtOfJustInsertedGraphic = 0;
3793 pFmtOfJustInsertedApo = 0;
3794 pPreviousNumPaM = 0;
3795 pPrevNumRule = 0;
3796 nAktColl = 0;
3797 nObjLocFc = nPicLocFc = 0;
3798 nInTable=0;
3799 bReadNoTbl = bPgSecBreak = bSpec = bObj = bTxbxFlySection
3800 = bHasBorder = bSymbol = bIgnoreText
3801 = bWasTabRowEnd = bWasTabCellEnd = false;
3802 bShdTxtCol = bCharShdTxtCol = bAnl = bHdFtFtnEdn = bFtnEdn
3803 = bIsHeader = bIsFooter = bIsUnicode = bCpxStyle = bStyNormal =
3804 bWWBugNormal = false;
3806 mpPostProcessAttrsInfo = 0;
3808 bNoAttrImport = bEmbeddObj = false;
3809 bAktAND_fNumberAcross = false;
3810 bNoLnNumYet = true;
3811 bInHyperlink = false;
3812 bWasParaEnd = false;
3813 bDropCap = false;
3814 bFirstPara = true;
3815 bFirstParaOfPage = false;//xushanchuan add for issue106569
3816 bParaAutoBefore = false;
3817 bParaAutoAfter = false;
3818 nProgress = 0;
3819 nSwNumLevel = nWwNumType = 0xff;
3820 pTableDesc = 0;
3821 pNumOlst = 0;
3822 pNode_FLY_AT_PARA = 0;
3823 pDrawModel = 0;
3824 pDrawPg = 0;
3825 mpDrawEditEngine = 0;
3826 pWWZOrder = 0;
3827 pFormImpl = 0;
3828 mpChosenOutlineNumRule = 0;
3829 pNumFldType = 0;
3830 nFldNum = 0;
3832 nLFOPosition = USHRT_MAX;
3833 nListLevel = WW8ListManager::nMaxLevel;
3834 eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
3836 nPgChpDelim = nPgChpLevel = 0;
3838 maApos.push_back(false);
3841 void SwWW8ImplReader::DeleteStk(SwFltControlStack* pStck)
3843 if( pStck )
3845 pStck->SetAttr( *pPaM->GetPoint(), 0, false);
3846 pStck->SetAttr( *pPaM->GetPoint(), 0, false);
3847 delete pStck;
3849 else
3851 OSL_ENSURE( !this, "WW-Stack bereits geloescht" );
3855 void wwSectionManager::SetSegmentToPageDesc(const wwSection &rSection,
3856 bool bIgnoreCols)
3858 SwPageDesc &rPage = *rSection.mpPage;
3860 SetNumberingType(rSection, rPage);
3862 SwFrmFmt &rFmt = rPage.GetMaster();
3864 if(mrReader.pWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
3865 mrReader.GrafikCtor();
3868 if (mrReader.pWDop->fUseBackGroundInAllmodes && mrReader.pMSDffManager)
3870 Rectangle aRect(0, 0, 100, 100); //A dummy, we don't care about the size
3871 SvxMSDffImportData aData(aRect);
3872 SdrObject* pObject = 0;
3873 if (mrReader.pMSDffManager->GetShape(0x401, pObject, aData))
3875 // Only handle shape if it is a background shape
3876 if ((aData.begin()->nFlags & 0x400) != 0)
3878 SfxItemSet aSet(rFmt.GetAttrSet());
3879 mrReader.MatchSdrItemsIntoFlySet(pObject, aSet, mso_lineSimple,
3880 mso_lineSolid, mso_sptRectangle, aRect);
3881 rFmt.SetFmtAttr(aSet.Get(RES_BACKGROUND));
3885 wwULSpaceData aULData;
3886 GetPageULData(rSection, aULData);
3887 SetPageULSpaceItems(rFmt, aULData, rSection);
3889 SetPage(rPage, rFmt, rSection, bIgnoreCols);
3891 if (!(rSection.maSep.pgbApplyTo & 1))
3892 mrReader.SetPageBorder(rFmt, rSection);
3893 if (!(rSection.maSep.pgbApplyTo & 2))
3894 mrReader.SetPageBorder(rPage.GetFirstMaster(), rSection);
3896 mrReader.SetDocumentGrid(rFmt, rSection);
3899 void wwSectionManager::SetUseOn(wwSection &rSection)
3901 bool bEven = (rSection.maSep.grpfIhdt & (WW8_HEADER_EVEN|WW8_FOOTER_EVEN)) ?
3902 true : false;
3904 bool bMirror = mrReader.pWDop->fMirrorMargins ||
3905 mrReader.pWDop->doptypography.f2on1;
3907 UseOnPage eUseBase = bMirror ? nsUseOnPage::PD_MIRROR : nsUseOnPage::PD_ALL;
3908 UseOnPage eUse = eUseBase;
3909 if (!bEven)
3910 eUse = (UseOnPage)(eUse | nsUseOnPage::PD_HEADERSHARE | nsUseOnPage::PD_FOOTERSHARE);
3911 if (!rSection.HasTitlePage())
3912 eUse = (UseOnPage)(eUse | nsUseOnPage::PD_FIRSTSHARE);
3914 OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
3915 if (rSection.mpPage)
3916 rSection.mpPage->WriteUseOn(eUse);
3919 //Set the page descriptor on this node, handle the different cases for a text
3920 //node or a table
3921 void GiveNodePageDesc(SwNodeIndex &rIdx, const SwFmtPageDesc &rPgDesc,
3922 SwDoc &rDoc)
3925 If its a table here, apply the pagebreak to the table
3926 properties, otherwise we add it to the para at this
3927 position
3929 if (rIdx.GetNode().IsTableNode())
3931 SwTable& rTable =
3932 rIdx.GetNode().GetTableNode()->GetTable();
3933 SwFrmFmt* pApply = rTable.GetFrmFmt();
3934 OSL_ENSURE(pApply, "impossible");
3935 if (pApply)
3936 pApply->SetFmtAttr(rPgDesc);
3938 else
3940 SwPosition aPamStart(rIdx);
3941 aPamStart.nContent.Assign(
3942 rIdx.GetNode().GetCntntNode(), 0);
3943 SwPaM aPage(aPamStart);
3945 rDoc.InsertPoolItem(aPage, rPgDesc, 0);
3949 //Map a word section to a writer page descriptor
3950 SwFmtPageDesc wwSectionManager::SetSwFmtPageDesc(mySegIter &rIter,
3951 mySegIter &rStart, bool bIgnoreCols)
3953 SwFmtPageDesc aEmpty;
3955 if (IsNewDoc() && rIter == rStart)
3957 rIter->mpPage =
3958 mrReader.rDoc.GetPageDescFromPool(RES_POOLPAGE_STANDARD);
3960 else
3962 sal_uInt16 nPos = mrReader.rDoc.MakePageDesc(
3963 ViewShell::GetShellRes()->GetPageDescName(mnDesc, ShellResource::NORMAL_PAGE),
3964 0, false);
3965 rIter->mpPage = &mrReader.rDoc.GetPageDesc(nPos);
3967 OSL_ENSURE(rIter->mpPage, "no page!");
3968 if (!rIter->mpPage)
3969 return aEmpty;
3971 //Set page before hd/ft
3972 const wwSection *pPrevious = 0;
3973 if (rIter != rStart)
3974 pPrevious = &(*(rIter-1));
3975 SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
3976 SetUseOn(*rIter);
3978 //Set hd/ft after set page
3979 SetSegmentToPageDesc(*rIter, bIgnoreCols);
3981 SwFmtPageDesc aRet(rIter->mpPage);
3983 rIter->mpPage->SetFollow(rIter->mpPage);
3985 if (rIter->PageRestartNo())
3986 aRet.SetNumOffset(rIter->PageStartAt());
3988 ++mnDesc;
3989 return aRet;
3992 bool wwSectionManager::IsNewDoc() const
3994 return mrReader.mbNewDoc;
3997 void wwSectionManager::InsertSegments()
3999 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
4000 sal_Bool bUseEnhFields = rOpt.IsUseEnhancedFields();
4001 mySegIter aEnd = maSegments.end();
4002 mySegIter aStart = maSegments.begin();
4003 for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4005 // If the section is of type "New column" (0x01), then simply insert a column break.
4006 // But only if there actually are columns on the page, otherwise a column break
4007 // seems to be handled like a page break by MSO.
4008 if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4010 SwPaM start( aIter->maStart );
4011 mrReader.rDoc.InsertPoolItem( start, SvxFmtBreakItem(SVX_BREAK_COLUMN_BEFORE, RES_BREAK), 0);
4012 continue;
4015 mySegIter aNext = aIter+1;
4016 mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4018 // If two following sections are different in following properties, Word will interprete a continuous
4019 // section break between them as if it was a section break next page.
4020 bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4021 (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4023 bool bInsertSection = (aIter != aStart) ? (aIter->IsContinous() && bThisAndPreviousAreCompatible): false;
4024 bool bInsertPageDesc = !bInsertSection;
4025 bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4026 if (bUseEnhFields && mrReader.pWDop->fProtEnabled && aIter->IsNotProtected())
4028 // here we have the special case that the whole document is protected, with the execption of this section.
4029 // I want to address this when I do the section rework, so for the moment we disable the overall protection then...
4030 mrReader.rDoc.set(IDocumentSettingAccess::PROTECT_FORM, false );
4034 if (bInsertPageDesc)
4037 If a cont section follows this section then we won't be
4038 creating a page desc with 2+ cols as we cannot host a one
4039 col section in a 2+ col pagedesc and make it look like
4040 word. But if the current section actually has columns then
4041 we are forced to insert a section here as well as a page
4042 descriptor.
4045 bool bIgnoreCols = false;
4046 bool bThisAndNextAreCompatible = (aNext != aEnd) ? ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4047 (aIter->GetPageHeight() == aNext->GetPageHeight()) && (aIter->IsLandScape() == aNext->IsLandScape())) : true;
4049 if (((aNext != aEnd && aNext->IsContinous() && bThisAndNextAreCompatible) || bProtected))
4051 bIgnoreCols = true;
4052 if ((aIter->NoCols() > 1) || bProtected)
4053 bInsertSection = true;
4056 SwFmtPageDesc aDesc(SetSwFmtPageDesc(aIter, aStart, bIgnoreCols));
4057 if (!aDesc.GetPageDesc())
4058 continue;
4060 // special case handling for odd/even section break
4061 // a) as before create a new page style for the section break
4062 // b) set Layout of generated page style to right/left ( according
4063 // to section break odd/even )
4064 // c) create a new style to follow the break page style
4065 if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4067 // SetSwFmtPageDesc calls some methods that could
4068 // modify aIter (e.g. wwSection ).
4069 // Since we call SetSwFmtPageDesc below to generate the
4070 // 'Following' style of the Break style, it is safer
4071 // to take a copy of the contents of aIter.
4072 wwSection aTmpSection = *aIter;
4073 // create a new following page style
4074 SwFmtPageDesc aFollow(SetSwFmtPageDesc(aIter, aStart, bIgnoreCols));
4075 // restore any contents of aIter trashed by SetSwFmtPageDesc
4076 *aIter = aTmpSection;
4078 // Handle the section break
4079 UseOnPage eUseOnPage = nsUseOnPage::PD_LEFT;
4080 if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4081 eUseOnPage = nsUseOnPage::PD_RIGHT;
4083 aDesc.GetPageDesc()->WriteUseOn( eUseOnPage );
4084 aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4087 GiveNodePageDesc(aIter->maStart, aDesc, mrReader.rDoc);
4090 SwTxtNode* pTxtNd = 0;
4091 if (bInsertSection)
4093 //Start getting the bounds of this section
4094 SwPaM aSectPaM(*mrReader.pPaM);
4095 SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4096 if (aNext != aEnd)
4098 aAnchor = aNext->maStart;
4099 aSectPaM.GetPoint()->nNode = aAnchor;
4100 aSectPaM.GetPoint()->nContent.Assign(
4101 aNext->maStart.GetNode().GetCntntNode(), 0);
4102 aSectPaM.Move(fnMoveBackward);
4105 const SwPosition* pPos = aSectPaM.GetPoint();
4106 SwTxtNode const*const pSttNd = pPos->nNode.GetNode().GetTxtNode();
4107 const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : 0;
4108 if (pTableNd)
4110 pTxtNd =
4111 mrReader.rDoc.GetNodes().MakeTxtNode(aAnchor,
4112 mrReader.rDoc.GetTxtCollFromPool( RES_POOLCOLL_TEXT ));
4114 aSectPaM.GetPoint()->nNode = SwNodeIndex(*pTxtNd);
4115 aSectPaM.GetPoint()->nContent.Assign(
4116 aSectPaM.GetCntntNode(), 0);
4119 aSectPaM.SetMark();
4121 aSectPaM.GetPoint()->nNode = aIter->maStart;
4122 aSectPaM.GetPoint()->nContent.Assign(
4123 aSectPaM.GetCntntNode(), 0);
4124 //End getting the bounds of this section, quite a job eh ?
4126 SwSectionFmt *pRet = InsertSection(aSectPaM, *aIter);
4127 //The last section if continous is always unbalanced
4128 if (pRet)
4130 //Set the columns to be UnBalanced if that compatability option
4131 //is set
4132 if (mrReader.pWDop->fNoColumnBalance)
4133 pRet->SetFmtAttr(SwFmtNoBalancedColumns(true));
4134 else
4136 //Otherwise set to unbalanced if the following section is
4137 //not continuous, (which also means that the last section
4138 //is unbalanced)
4139 if (aNext == aEnd || !aNext->IsContinous())
4140 pRet->SetFmtAttr(SwFmtNoBalancedColumns(true));
4144 bool bHasOwnHdFt = false;
4146 In this nightmare scenario the continuous section has its own
4147 headers and footers so we will try and find a hard page break
4148 between here and the end of the section and put the headers and
4149 footers there.
4151 if (!bInsertPageDesc)
4153 bHasOwnHdFt =
4154 mrReader.HasOwnHeaderFooter(
4155 aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4156 aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4159 if (bHasOwnHdFt)
4161 // #i40766# Need to cache the page descriptor in case there is
4162 // no page break in the section
4163 SwPageDesc *pOrig = aIter->mpPage;
4164 bool bFailed = true;
4165 SwFmtPageDesc aDesc(SetSwFmtPageDesc(aIter, aStart, true));
4166 if (aDesc.GetPageDesc())
4168 sal_uLong nStart = aSectPaM.Start()->nNode.GetIndex();
4169 sal_uLong nEnd = aSectPaM.End()->nNode.GetIndex();
4170 for(; nStart <= nEnd; ++nStart)
4172 SwNode* pNode = mrReader.rDoc.GetNodes()[nStart];
4173 if (!pNode)
4174 continue;
4175 if (sw::util::HasPageBreak(*pNode))
4177 SwNodeIndex aIdx(*pNode);
4178 GiveNodePageDesc(aIdx, aDesc, mrReader.rDoc);
4179 bFailed = false;
4180 break;
4184 if(bFailed)
4186 aIter->mpPage = pOrig;
4191 if (pTxtNd)
4193 SwNodeIndex aIdx(*pTxtNd);
4194 SwPaM aTest(aIdx);
4195 mrReader.rDoc.DelFullPara(aTest);
4196 pTxtNd = 0;
4201 void wwExtraneousParas::delete_all_from_doc()
4203 typedef std::vector<SwTxtNode*>::iterator myParaIter;
4204 myParaIter aEnd = m_aTxtNodes.end();
4205 for (myParaIter aI = m_aTxtNodes.begin(); aI != aEnd; ++aI)
4207 SwTxtNode *pTxtNode = *aI;
4208 SwNodeIndex aIdx(*pTxtNode);
4209 SwPaM aTest(aIdx);
4210 m_rDoc.DelFullPara(aTest);
4212 m_aTxtNodes.clear();
4215 void SwWW8ImplReader::StoreMacroCmds()
4217 if (pWwFib->lcbCmds)
4219 pTableStream->Seek(pWwFib->fcCmds);
4221 uno::Reference < embed::XStorage > xRoot(mpDocShell->GetStorage());
4223 if (!xRoot.is())
4224 return;
4228 uno::Reference < io::XStream > xStream =
4229 xRoot->openStreamElement( OUString(SL::aMSMacroCmds), embed::ElementModes::READWRITE );
4230 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( xStream );
4232 sal_uInt8 *pBuffer = new sal_uInt8[pWwFib->lcbCmds];
4233 pWwFib->lcbCmds = pTableStream->Read(pBuffer, pWwFib->lcbCmds);
4234 pStream->Write(pBuffer, pWwFib->lcbCmds);
4235 delete[] pBuffer;
4236 delete pStream;
4238 catch ( const uno::Exception& )
4244 void SwWW8ImplReader::ReadDocVars()
4246 std::vector<String> aDocVarStrings;
4247 std::vector<ww::bytes> aDocVarStringIds;
4248 std::vector<String> aDocValueStrings;
4249 WW8ReadSTTBF(!bVer67, *pTableStream, pWwFib->fcStwUser,
4250 pWwFib->lcbStwUser, bVer67 ? 2 : 0, eStructCharSet,
4251 aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4252 if (!bVer67) {
4253 using namespace ::com::sun::star;
4255 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4256 mpDocShell->GetModel(), uno::UNO_QUERY_THROW);
4257 uno::Reference<document::XDocumentProperties> xDocProps(
4258 xDPS->getDocumentProperties());
4259 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4260 uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4261 xDocProps->getUserDefinedProperties();
4262 OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null");
4264 for(size_t i=0; i<aDocVarStrings.size(); i++)
4266 uno::Any aDefaultValue;
4267 OUString name(aDocVarStrings[i]);
4268 uno::Any aValue;
4269 aValue <<= OUString(aDocValueStrings[i]);
4270 try {
4271 xUserDefinedProps->addProperty( name,
4272 beans::PropertyAttribute::REMOVABLE,
4273 aValue );
4274 } catch (const uno::Exception &) {
4275 // ignore
4281 //-----------------------------------------
4282 // Document Info
4283 //-----------------------------------------
4285 void SwWW8ImplReader::ReadDocInfo()
4287 if( pStg )
4289 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4290 mpDocShell->GetModel(), uno::UNO_QUERY_THROW);
4291 uno::Reference<document::XDocumentProperties> xDocProps(
4292 xDPS->getDocumentProperties());
4293 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4295 if (xDocProps.is()) {
4296 if ( pWwFib->fDot )
4298 OUString sTemplateURL;
4299 SfxMedium* pMedium = mpDocShell->GetMedium();
4300 if ( pMedium )
4302 OUString aName = pMedium->GetName();
4303 INetURLObject aURL( aName );
4304 sTemplateURL = aURL.GetMainURL(INetURLObject::DECODE_TO_IURI);
4305 if ( !sTemplateURL.isEmpty() )
4306 xDocProps->setTemplateURL( sTemplateURL );
4309 else if (pWwFib->lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4311 long nCur = pTableStream->Tell();
4312 Sttb aSttb;
4313 pTableStream->Seek( pWwFib->fcSttbfAssoc ); // point at tgc record
4314 if (!aSttb.Read( *pTableStream ) )
4315 OSL_TRACE("** Read of SttbAssoc data failed!!!! ");
4316 pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4317 #if OSL_DEBUG_LEVEL > 1
4318 aSttb.Print( stderr );
4319 #endif
4320 String sPath = aSttb.getStringAtIndex( 0x1 );
4321 OUString aURL;
4322 // attempt to convert to url ( won't work for obvious reasons on linux
4323 if ( sPath.Len() )
4324 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sPath, aURL );
4325 if (aURL.isEmpty())
4326 xDocProps->setTemplateURL( aURL );
4327 else
4328 xDocProps->setTemplateURL( sPath );
4331 sfx2::LoadOlePropertySet(xDocProps, pStg);
4336 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4338 if ( xPrjNameCache.is() )
4340 INetURLObject aObj;
4341 aObj.SetURL( sTemplatePathOrURL );
4342 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
4343 OUString aURL;
4344 if ( bIsURL )
4345 aURL = sTemplatePathOrURL;
4346 else
4348 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4349 aObj.SetURL( aURL );
4353 OUString templateNameWithExt = aObj.GetLastName();
4354 OUString templateName;
4355 sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4356 if ( nIndex != -1 )
4358 templateName = templateNameWithExt.copy( 0, nIndex );
4359 xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4362 catch( const uno::Exception& )
4368 class WW8Customizations
4370 SvStream* mpTableStream;
4371 WW8Fib mWw8Fib;
4372 public:
4373 WW8Customizations( SvStream*, WW8Fib& );
4374 bool Import( SwDocShell* pShell );
4377 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib& rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4381 bool WW8Customizations::Import( SwDocShell* pShell )
4383 if ( mWw8Fib.lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4384 return false;
4387 Tcg aTCG;
4388 long nCur = mpTableStream->Tell();
4389 mpTableStream->Seek( mWw8Fib.fcCmds ); // point at tgc record
4390 bool bReadResult = aTCG.Read( *mpTableStream );
4391 mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4392 if ( !bReadResult )
4394 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4395 return false;
4397 #if OSL_DEBUG_LEVEL > 1
4398 aTCG.Print( stderr );
4399 #endif
4400 return aTCG.ImportCustomToolBar( *pShell );
4402 catch(...)
4404 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4405 return false;
4409 bool SwWW8ImplReader::ReadGlobalTemplateSettings( const OUString& sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4411 SvtPathOptions aPathOpt;
4412 String aAddinPath = aPathOpt.GetAddinPath();
4413 uno::Sequence< OUString > sGlobalTemplates;
4415 // first get the autoload addins in the directory STARTUP
4416 uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4418 if( xSFA->isFolder( aAddinPath ) )
4419 sGlobalTemplates = xSFA->getFolderContents( aAddinPath, sal_False );
4421 sal_Int32 nEntries = sGlobalTemplates.getLength();
4422 bool bRes = true;
4423 for ( sal_Int32 i=0; i<nEntries; ++i )
4425 INetURLObject aObj;
4426 aObj.SetURL( sGlobalTemplates[ i ] );
4427 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
4428 OUString aURL;
4429 if ( bIsURL )
4430 aURL = sGlobalTemplates[ i ];
4431 else
4432 osl::FileBase::getFileURLFromSystemPath( sGlobalTemplates[ i ], aURL );
4433 if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.isEmpty() && sCreatedFrom.equals( aURL ) ) )
4434 continue; // don't try and read the same document as ourselves
4436 SotStorageRef rRoot = new SotStorage( aURL, STREAM_STD_READWRITE, STORAGE_TRANSACTED );
4438 BasicProjImportHelper aBasicImporter( *mpDocShell );
4439 // Import vba via oox filter
4440 aBasicImporter.import( mpDocShell->GetMedium()->GetInputStream() );
4441 lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4442 // Read toolbars & menus
4443 SvStorageStreamRef refMainStream = rRoot->OpenSotStream( OUString( "WordDocument" ));
4444 refMainStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
4445 WW8Fib aWwFib( *refMainStream, 8 );
4446 SvStorageStreamRef xTableStream = rRoot->OpenSotStream(OUString::createFromAscii( aWwFib.fWhichTblStm ? SL::a1Table : SL::a0Table), STREAM_STD_READ);
4448 if (xTableStream.Is() && SVSTREAM_OK == xTableStream->GetError())
4450 xTableStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
4451 WW8Customizations aGblCustomisations( xTableStream, aWwFib );
4452 aGblCustomisations.Import( mpDocShell );
4455 return bRes;
4458 sal_uLong SwWW8ImplReader::CoreLoad(WW8Glossary *pGloss, const SwPosition &rPos)
4460 sal_uLong nErrRet = 0;
4462 if (mbNewDoc && pStg && !pGloss)
4463 ReadDocInfo();
4465 ::ww8::WW8FibData * pFibData = new ::ww8::WW8FibData();
4467 if (pWwFib->fReadOnlyRecommended)
4468 pFibData->setReadOnlyRecommended(true);
4469 else
4470 pFibData->setReadOnlyRecommended(false);
4472 if (pWwFib->fWriteReservation)
4473 pFibData->setWriteReservation(true);
4474 else
4475 pFibData->setWriteReservation(false);
4477 ::sw::tExternalDataPointer pExternalFibData(pFibData);
4479 rDoc.setExternalData(::sw::FIB, pExternalFibData);
4481 ::sw::tExternalDataPointer pSttbfAsoc
4482 (new ::ww8::WW8Sttb<ww8::WW8Struct>(*pTableStream, pWwFib->fcSttbfAssoc, pWwFib->lcbSttbfAssoc));
4484 rDoc.setExternalData(::sw::STTBF_ASSOC, pSttbfAsoc);
4486 if (pWwFib->fWriteReservation || pWwFib->fReadOnlyRecommended)
4488 SwDocShell * pDocShell = rDoc.GetDocShell();
4489 if (pDocShell)
4490 pDocShell->SetReadOnlyUI(sal_True);
4493 pPaM = new SwPaM(rPos);
4495 pCtrlStck = new SwWW8FltControlStack( &rDoc, nFieldFlags, *this );
4497 mpRedlineStack = new sw::util::RedlineStack(rDoc);
4500 RefFldStck: Keeps track of bookmarks which may be inserted as
4501 variables intstead.
4503 pReffedStck = new SwFltEndStack(&rDoc, nFieldFlags);
4504 pReffingStck = new SwWW8FltRefStack(&rDoc, nFieldFlags);
4506 pAnchorStck = new SwWW8FltAnchorStack(&rDoc, nFieldFlags);
4508 sal_uInt16 nPageDescOffset = rDoc.GetPageDescCnt();
4510 SwNodeIndex aSttNdIdx( rDoc.GetNodes() );
4511 SwRelNumRuleSpaces aRelNumRule(rDoc, mbNewDoc);
4513 sal_uInt16 eMode = nsRedlineMode_t::REDLINE_SHOW_INSERT;
4515 mpSprmParser = new wwSprmParser(pWwFib->GetFIBVersion());
4517 // praktische Hilfsvariablen besetzen:
4518 bVer6 = (6 == pWwFib->nVersion);
4519 bVer7 = (7 == pWwFib->nVersion);
4520 bVer67 = bVer6 || bVer7;
4521 bVer8 = (8 == pWwFib->nVersion);
4523 eTextCharSet = WW8Fib::GetFIBCharset(pWwFib->chse);
4524 eStructCharSet = WW8Fib::GetFIBCharset(pWwFib->chseTables);
4526 bWWBugNormal = pWwFib->nProduct == 0xc03d;
4528 if (!mbNewDoc)
4529 aSttNdIdx = pPaM->GetPoint()->nNode;
4531 ::StartProgress(STR_STATSTR_W4WREAD, 0, 100, mpDocShell);
4533 // read Font Table
4534 pFonts = new WW8Fonts( *pTableStream, *pWwFib );
4536 // Document Properties
4537 pWDop = new WW8Dop( *pTableStream, pWwFib->nFib, pWwFib->fcDop,
4538 pWwFib->lcbDop );
4540 if (mbNewDoc)
4541 ImportDop();
4544 Import revisioning data: author names
4546 if( pWwFib->lcbSttbfRMark )
4548 ReadRevMarkAuthorStrTabl( *pTableStream,
4549 pWwFib->fcSttbfRMark,
4550 pWwFib->lcbSttbfRMark, rDoc );
4553 // M.M. Initialize our String/ID map for Linked Sections
4554 std::vector<String> aLinkStrings;
4555 std::vector<ww::bytes> aStringIds;
4557 WW8ReadSTTBF(!bVer67, *pTableStream, pWwFib->fcSttbFnm,
4558 pWwFib->lcbSttbFnm, bVer67 ? 2 : 0, eStructCharSet,
4559 aLinkStrings, &aStringIds);
4561 for (size_t i=0; i < aLinkStrings.size() && i < aStringIds.size(); ++i)
4563 ww::bytes stringId = aStringIds[i];
4564 WW8_STRINGID *stringIdStruct = (WW8_STRINGID*)(&stringId[0]);
4565 aLinkStringMap[SVBT16ToShort(stringIdStruct->nStringId)] =
4566 aLinkStrings[i];
4569 ReadDocVars(); // import document variables as meta information.
4571 ::SetProgressState(nProgress, mpDocShell); // Update
4573 pLstManager = new WW8ListManager( *pTableStream, *this );
4576 zuerst(!) alle Styles importieren (siehe WW8PAR2.CXX)
4577 VOR dem Import der Listen !!
4579 ::SetProgressState(nProgress, mpDocShell); // Update
4580 pStyles = new WW8RStyle( *pWwFib, this ); // Styles
4581 pStyles->Import();
4584 zu guter Letzt: (siehe ebenfalls WW8PAR3.CXX)
4585 ===============
4586 alle Styles durchgehen und ggfs. zugehoeriges Listen-Format
4587 anhaengen NACH dem Import der Styles und NACH dem Import der
4588 Listen !!
4590 ::SetProgressState(nProgress, mpDocShell); // Update
4591 pStyles->PostProcessStyles();
4593 if (!vColl.empty())
4594 SetOutLineStyles();
4596 pSBase = new WW8ScannerBase(pStrm,pTableStream,pDataStream,pWwFib);
4598 static const SvxExtNumType eNumTA[16] =
4600 SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
4601 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N,
4602 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
4603 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
4604 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
4605 SVX_NUM_ARABIC, SVX_NUM_ARABIC
4608 if (pSBase->AreThereFootnotes())
4610 static const SwFtnNum eNumA[4] =
4612 FTNNUM_DOC, FTNNUM_CHAPTER, FTNNUM_PAGE, FTNNUM_DOC
4615 SwFtnInfo aInfo;
4616 aInfo = rDoc.GetFtnInfo(); // Copy-Ctor privat
4618 aInfo.ePos = FTNPOS_PAGE;
4619 aInfo.eNum = eNumA[pWDop->rncFtn];
4620 aInfo.aFmt.SetNumberingType( static_cast< sal_uInt16 >(eNumTA[pWDop->nfcFtnRef]) );
4621 if( pWDop->nFtn )
4622 aInfo.nFtnOffset = pWDop->nFtn - 1;
4623 rDoc.SetFtnInfo( aInfo );
4625 if( pSBase->AreThereEndnotes() )
4627 SwEndNoteInfo aInfo;
4628 aInfo = rDoc.GetEndNoteInfo(); // parallel zu Ftn
4630 aInfo.aFmt.SetNumberingType( static_cast< sal_uInt16 >(eNumTA[pWDop->nfcEdnRef]) );
4631 if( pWDop->nEdn )
4632 aInfo.nFtnOffset = pWDop->nEdn - 1;
4633 rDoc.SetEndNoteInfo( aInfo );
4636 if( pWwFib->lcbPlcfhdd )
4637 pHdFt = new WW8PLCF_HdFt( pTableStream, *pWwFib, *pWDop );
4639 if (!mbNewDoc)
4641 // inserting into an existing document:
4642 // As only complete paragraphs are inserted, the current one
4643 // needs to be splitted - once or even twice.
4644 const SwPosition* pPos = pPaM->GetPoint();
4646 // split current paragraph to get new paragraph for the insertion
4647 rDoc.SplitNode( *pPos, false );
4649 // another split, if insertion position was not at the end of the current paragraph.
4650 SwTxtNode const*const pTxtNd = pPos->nNode.GetNode().GetTxtNode();
4651 if ( pTxtNd->GetTxt().getLength() )
4653 rDoc.SplitNode( *pPos, false );
4654 // move PaM back to the newly empty paragraph
4655 pPaM->Move( fnMoveBackward );
4658 // suppress insertion of tables inside footnotes.
4659 const sal_uLong nNd = pPos->nNode.GetIndex();
4660 bReadNoTbl = ( nNd < rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
4661 rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd );
4665 ::SetProgressState(nProgress, mpDocShell); // Update
4667 // loop for each glossary entry and add dummy section node
4668 if (pGloss)
4670 WW8PLCF aPlc(*pTableStream, pWwFib->fcPlcfglsy, pWwFib->lcbPlcfglsy, 0);
4672 WW8_CP nStart, nEnd;
4673 void* pDummy;
4675 for (int i = 0; i < pGloss->GetNoStrings(); ++i, aPlc.advance())
4677 SwNodeIndex aIdx( rDoc.GetNodes().GetEndOfContent());
4678 SwTxtFmtColl* pColl =
4679 rDoc.GetTxtCollFromPool(RES_POOLCOLL_STANDARD,
4680 false);
4681 SwStartNode *pNode =
4682 rDoc.GetNodes().MakeTextSection(aIdx,
4683 SwNormalStartNode,pColl);
4684 pPaM->GetPoint()->nNode = pNode->GetIndex()+1;
4685 pPaM->GetPoint()->nContent.Assign(pPaM->GetCntntNode(),0);
4686 aPlc.Get( nStart, nEnd, pDummy );
4687 ReadText(nStart,nEnd-nStart-1,MAN_MAINTEXT);
4690 else //ordinary case
4692 if (mbNewDoc && pStg && !pGloss) /*meaningless for a glossary, cmc*/
4694 mpDocShell->SetIsTemplate( pWwFib->fDot ); // point at tgc record
4695 uno::Reference<document::XDocumentPropertiesSupplier> const
4696 xDocPropSupp(mpDocShell->GetModel(), uno::UNO_QUERY_THROW);
4697 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
4699 OUString sCreatedFrom = xDocProps->getTemplateURL();
4700 uno::Reference< container::XNameContainer > xPrjNameCache;
4701 uno::Reference< lang::XMultiServiceFactory> xSF(mpDocShell->GetModel(), uno::UNO_QUERY);
4702 if ( xSF.is() )
4703 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
4705 // Read Global templates
4706 ReadGlobalTemplateSettings( sCreatedFrom, xPrjNameCache );
4708 // Create and insert Word vba Globals
4709 uno::Any aGlobs;
4710 uno::Sequence< uno::Any > aArgs(1);
4711 aArgs[ 0 ] <<= mpDocShell->GetModel();
4712 aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs );
4714 #ifndef DISABLE_SCRIPTING
4715 BasicManager *pBasicMan = mpDocShell->GetBasicManager();
4716 if (pBasicMan)
4717 pBasicMan->SetGlobalUNOConstant( "VBAGlobals", aGlobs );
4718 #endif
4719 BasicProjImportHelper aBasicImporter( *mpDocShell );
4720 // Import vba via oox filter
4721 bool bRet = aBasicImporter.import( mpDocShell->GetMedium()->GetInputStream() );
4723 lcl_createTemplateToProjectEntry( xPrjNameCache, sCreatedFrom, aBasicImporter.getProjectName() );
4724 WW8Customizations aCustomisations( pTableStream, *pWwFib );
4725 aCustomisations.Import( mpDocShell );
4727 if( bRet )
4728 rDoc.SetContainsMSVBasic(true);
4730 StoreMacroCmds();
4732 mbOnLoadingMain = true;
4733 ReadText(0, pWwFib->ccpText, MAN_MAINTEXT);
4734 mbOnLoadingMain = false;
4738 ::SetProgressState(nProgress, mpDocShell); // Update
4740 if (pDrawPg && pMSDffManager && pMSDffManager->GetShapeOrders())
4742 // Hilfsarray zum Verketten der (statt SdrTxtObj) eingefuegten
4743 // Rahmen
4744 SvxMSDffShapeTxBxSort aTxBxSort;
4746 // korrekte Z-Order der eingelesen Escher-Objekte sicherstellen
4747 sal_uInt16 nShapeCount = pMSDffManager->GetShapeOrders()->size();
4749 for (sal_uInt16 nShapeNum=0; nShapeNum < nShapeCount; nShapeNum++)
4751 SvxMSDffShapeOrder *pOrder =
4752 (*pMSDffManager->GetShapeOrders())[nShapeNum];
4753 // Pointer in neues Sort-Array einfuegen
4754 if (pOrder->nTxBxComp && pOrder->pFly)
4755 aTxBxSort.insert(pOrder);
4757 // zu verkettende Rahmen jetzt verketten
4758 if( !aTxBxSort.empty() )
4760 SwFmtChain aChain;
4761 for( SvxMSDffShapeTxBxSort::iterator it = aTxBxSort.begin(); it != aTxBxSort.end(); ++it )
4763 SvxMSDffShapeOrder *pOrder = *it;
4765 // Fly-Frame-Formate initialisieren
4766 SwFlyFrmFmt* pFlyFmt = pOrder->pFly;
4767 SwFlyFrmFmt* pNextFlyFmt = 0;
4768 SwFlyFrmFmt* pPrevFlyFmt = 0;
4769 // ggfs. Nachfolger ermitteln
4770 SvxMSDffShapeTxBxSort::iterator tmpIter1 = it;
4771 ++tmpIter1;
4772 if( tmpIter1 != aTxBxSort.end() )
4774 SvxMSDffShapeOrder *pNextOrder = *tmpIter1;
4775 if ((0xFFFF0000 & pOrder->nTxBxComp)
4776 == (0xFFFF0000 & pNextOrder->nTxBxComp))
4777 pNextFlyFmt = pNextOrder->pFly;
4779 // ggfs. Vorgaenger ermitteln
4780 if( it != aTxBxSort.begin() )
4782 SvxMSDffShapeTxBxSort::iterator tmpIter2 = it;
4783 --tmpIter2;
4784 SvxMSDffShapeOrder *pPrevOrder = *tmpIter2;
4785 if ((0xFFFF0000 & pOrder->nTxBxComp)
4786 == (0xFFFF0000 & pPrevOrder->nTxBxComp))
4787 pPrevFlyFmt = pPrevOrder->pFly;
4789 // Falls Nachfolger oder Vorgaenger vorhanden,
4790 // die Verkettung am Fly-Frame-Format eintragen
4791 if (pNextFlyFmt || pPrevFlyFmt)
4793 aChain.SetNext( pNextFlyFmt );
4794 aChain.SetPrev( pPrevFlyFmt );
4795 pFlyFmt->SetFmtAttr( aChain );
4803 if (mbNewDoc)
4805 if( pWDop->fRevMarking )
4806 eMode |= nsRedlineMode_t::REDLINE_ON;
4807 if( pWDop->fRMView )
4808 eMode |= nsRedlineMode_t::REDLINE_SHOW_DELETE;
4811 maInsertedTables.DelAndMakeTblFrms();
4812 maSectionManager.InsertSegments();
4814 vColl.clear();
4816 DELETEZ( pStyles );
4818 if( pFormImpl )
4819 DeleteFormImpl();
4820 GrafikDtor();
4821 DELETEZ( pMSDffManager );
4822 DELETEZ( pHdFt );
4823 DELETEZ( pSBase );
4824 delete pWDop;
4825 DELETEZ( pFonts );
4826 delete mpAtnNames;
4827 delete mpSprmParser;
4828 ::EndProgress(mpDocShell);
4830 pDataStream = 0;
4831 pTableStream = 0;
4833 DeleteCtrlStk();
4834 mpRedlineStack->closeall(*pPaM->GetPoint());
4835 delete mpRedlineStack;
4836 DeleteAnchorStk();
4837 DeleteRefStks();
4838 //For i120928,achieve the graphics from the special bookmark with is for graphic bullet
4840 std::vector<const SwGrfNode*> vecBulletGrf;
4841 std::vector<SwFrmFmt*> vecFrmFmt;
4843 IDocumentMarkAccess* const pMarkAccess =
4844 rDoc.getIDocumentMarkAccess();
4845 if ( pMarkAccess )
4847 IDocumentMarkAccess::const_iterator_t ppBkmk =
4848 pMarkAccess->findBookmark( "_PictureBullets" );
4849 if ( ppBkmk != pMarkAccess->getBookmarksEnd() &&
4850 IDocumentMarkAccess::GetType( *(ppBkmk->get()) )
4851 == IDocumentMarkAccess::BOOKMARK )
4853 SwTxtNode* pTxtNode = ppBkmk->get()->GetMarkStart().nNode.GetNode().GetTxtNode();
4854 if ( pTxtNode )
4856 const SwpHints *pHints = pTxtNode->GetpSwpHints();
4857 for(int nHintPos = 0; pHints && nHintPos < pHints->Count(); ++nHintPos)
4859 const SwTxtAttr *pHt = (*pHints)[nHintPos];
4860 xub_StrLen st = *(pHt->GetStart());
4861 if(pHt && pHt->Which() == RES_TXTATR_FLYCNT && (st >= ppBkmk->get()->GetMarkStart().nContent.GetIndex()))
4863 SwFrmFmt *pFrmFmt = pHt->GetFlyCnt().GetFrmFmt();
4864 const SwNodeIndex *pNdIdx = pFrmFmt->GetCntnt().GetCntntIdx();
4865 if (pNdIdx)
4867 const SwNodes &nos = pNdIdx->GetNodes();
4868 const SwGrfNode *pGrf = dynamic_cast<const SwGrfNode*>(nos[pNdIdx->GetIndex() + 1]);
4869 if (pGrf)
4871 vecBulletGrf.push_back(pGrf);
4872 vecFrmFmt.push_back(pFrmFmt);
4877 // update graphic bullet information
4878 size_t nCount = pLstManager->GetWW8LSTInfoNum();
4879 for (size_t i = 0; i < nCount; ++i)
4881 SwNumRule* pRule = pLstManager->GetNumRule(i);
4882 for (int j = 0; j < MAXLEVEL; ++j)
4884 SwNumFmt aNumFmt(pRule->Get(j));
4885 sal_Int16 nType = aNumFmt.GetNumberingType();
4886 sal_uInt16 nGrfBulletCP = aNumFmt.GetGrfBulletCP();
4887 if (nType == SVX_NUM_BITMAP && vecBulletGrf.size() > nGrfBulletCP)
4889 Graphic aGraphic = vecBulletGrf[nGrfBulletCP]->GetGrf();
4890 SvxBrushItem aBrush(aGraphic, GPOS_AREA, SID_ATTR_BRUSH);
4891 Font aFont = numfunc::GetDefBulletFont();
4892 int nHeight = aFont.GetHeight() * 12;//20;
4893 Size aPrefSize( aGraphic.GetPrefSize());
4894 if (aPrefSize.Height() * aPrefSize.Width() != 0 )
4896 int nWidth = (nHeight * aPrefSize.Width()) / aPrefSize.Height();
4897 Size aSize(nWidth, nHeight);
4898 aNumFmt.SetGraphicBrush(&aBrush, &aSize);
4900 else
4902 aNumFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
4903 aNumFmt.SetBulletChar(0x2190);
4905 pRule->Set( j, aNumFmt );
4909 // Remove additional pictures
4910 for (sal_uInt16 i = 0; i < vecFrmFmt.size(); ++i)
4912 rDoc.DelLayoutFmt(vecFrmFmt[i]);
4917 DELETEZ( pLstManager );
4920 //remove extra paragraphs after attribute ctrl
4921 //stacks etc. are destroyed, and before fields
4922 //are updated
4923 m_aExtraneousParas.delete_all_from_doc();
4925 UpdateFields();
4927 // delete the pam before the call for hide all redlines (Bug 73683)
4928 if (mbNewDoc)
4929 rDoc.SetRedlineMode((RedlineMode_t)( eMode ));
4931 UpdatePageDescs(rDoc, nPageDescOffset);
4933 delete pPaM, pPaM = 0;
4934 return nErrRet;
4937 sal_uLong SwWW8ImplReader::SetSubStreams(SvStorageStreamRef &rTableStream,
4938 SvStorageStreamRef &rDataStream)
4940 sal_uLong nErrRet = 0;
4941 // 6 stands for "6 OR 7", 7 stand for "ONLY 7"
4942 switch (pWwFib->nVersion)
4944 case 6:
4945 case 7:
4946 pTableStream = pStrm;
4947 pDataStream = pStrm;
4948 break;
4949 case 8:
4950 if(!pStg)
4952 OSL_ENSURE( pStg, "Version 8 muss immer einen Storage haben!" );
4953 nErrRet = ERR_SWG_READ_ERROR;
4954 break;
4957 rTableStream = pStg->OpenSotStream( OUString::createFromAscii(
4958 pWwFib->fWhichTblStm ? SL::a1Table : SL::a0Table),
4959 STREAM_STD_READ);
4961 pTableStream = &rTableStream;
4962 pTableStream->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
4964 rDataStream = pStg->OpenSotStream(OUString(SL::aData),
4965 STREAM_STD_READ | STREAM_NOCREATE );
4967 if (rDataStream.Is() && SVSTREAM_OK == rDataStream->GetError())
4969 pDataStream = &rDataStream;
4970 pDataStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
4972 else
4973 pDataStream = pStrm;
4974 break;
4975 default:
4976 // Programm-Fehler!
4977 OSL_ENSURE( !this, "Es wurde vergessen, nVersion zu kodieren!" );
4978 nErrRet = ERR_SWG_READ_ERROR;
4979 break;
4981 return nErrRet;
4984 namespace
4986 utl::TempFile *MakeTemp(SvFileStream &rSt)
4988 utl::TempFile *pT = new utl::TempFile;
4989 pT->EnableKillingFile();
4990 rSt.Open(pT->GetFileName(), STREAM_READWRITE | STREAM_SHARE_DENYWRITE);
4991 return pT;
4994 #define WW_BLOCKSIZE 0x200
4996 void DecryptRC4(msfilter::MSCodec_Std97& rCtx, SvStream &rIn, SvStream &rOut)
4998 rIn.Seek(STREAM_SEEK_TO_END);
4999 const sal_Size nLen = rIn.Tell();
5000 rIn.Seek(0);
5002 sal_uInt8 in[WW_BLOCKSIZE];
5003 for (sal_Size nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
5005 sal_Size nBS = (nLen - nI > WW_BLOCKSIZE) ? WW_BLOCKSIZE : nLen - nI;
5006 nBS = rIn.Read(in, nBS);
5007 rCtx.InitCipher(nBlock);
5008 rCtx.Decode(in, nBS, in, nBS);
5009 rOut.Write(in, nBS);
5013 void DecryptXOR(msfilter::MSCodec_XorWord95 &rCtx, SvStream &rIn, SvStream &rOut)
5015 sal_Size nSt = rIn.Tell();
5016 rIn.Seek(STREAM_SEEK_TO_END);
5017 sal_Size nLen = rIn.Tell();
5018 rIn.Seek(nSt);
5020 rCtx.InitCipher();
5021 rCtx.Skip(nSt);
5023 sal_uInt8 in[0x4096];
5024 for (sal_Size nI = nSt; nI < nLen; nI += 0x4096)
5026 sal_Size nBS = (nLen - nI > 0x4096 ) ? 0x4096 : nLen - nI;
5027 nBS = rIn.Read(in, nBS);
5028 rCtx.Decode(in, nBS);
5029 rOut.Write(in, nBS);
5033 //moan, copy and paste :-(
5034 String QueryPasswordForMedium(SfxMedium& rMedium)
5036 String aPassw;
5038 using namespace com::sun::star;
5040 const SfxItemSet* pSet = rMedium.GetItemSet();
5041 const SfxPoolItem *pPasswordItem;
5043 if(pSet && SFX_ITEM_SET == pSet->GetItemState(SID_PASSWORD, sal_True, &pPasswordItem))
5044 aPassw = ((const SfxStringItem *)pPasswordItem)->GetValue();
5045 else
5049 uno::Reference< task::XInteractionHandler > xHandler( rMedium.GetInteractionHandler() );
5050 if( xHandler.is() )
5052 ::comphelper::DocPasswordRequest* pRequest = new ::comphelper::DocPasswordRequest(
5053 ::comphelper::DocPasswordRequestType_MS, task::PasswordRequestMode_PASSWORD_ENTER,
5054 INetURLObject( rMedium.GetOrigURL() ).GetName( INetURLObject::DECODE_WITH_CHARSET ) );
5055 uno::Reference< task::XInteractionRequest > xRequest( pRequest );
5057 xHandler->handle( xRequest );
5059 if( pRequest->isPassword() )
5060 aPassw = pRequest->getPassword();
5063 catch( const uno::Exception& )
5068 return aPassw;
5071 uno::Sequence< beans::NamedValue > InitXorWord95Codec( ::msfilter::MSCodec_XorWord95& rCodec, SfxMedium& rMedium, WW8Fib* pWwFib )
5073 uno::Sequence< beans::NamedValue > aEncryptionData;
5074 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pEncryptionData, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False );
5075 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5076 aEncryptionData.realloc( 0 );
5078 if ( !aEncryptionData.getLength() )
5080 String sUniPassword = QueryPasswordForMedium( rMedium );
5082 OString sPassword(OUStringToOString(sUniPassword,
5083 WW8Fib::GetFIBCharset(pWwFib->chseTables)));
5085 sal_Int32 nLen = sPassword.getLength();
5086 if( nLen <= 15 )
5088 sal_uInt8 pPassword[16];
5089 memcpy(pPassword, sPassword.getStr(), nLen);
5090 memset(pPassword+nLen, 0, sizeof(pPassword)-nLen);
5092 rCodec.InitKey( pPassword );
5093 aEncryptionData = rCodec.GetEncryptionData();
5095 // the export supports RC4 algorithm only, so we have to
5096 // generate the related EncryptionData as well, so that Save
5097 // can export the document without asking for a password;
5098 // as result there will be EncryptionData for both algorithms
5099 // in the MediaDescriptor
5100 ::msfilter::MSCodec_Std97 aCodec97;
5102 // Generate random number with a seed of time as salt.
5103 TimeValue aTime;
5104 osl_getSystemTime( &aTime );
5105 rtlRandomPool aRandomPool = rtl_random_createPool();
5106 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
5108 sal_uInt8 pDocId[ 16 ];
5109 rtl_random_getBytes( aRandomPool, pDocId, 16 );
5111 rtl_random_destroyPool( aRandomPool );
5113 sal_uInt16 pStd97Pass[16];
5114 memset( pStd97Pass, 0, sizeof( pStd97Pass ) );
5115 for (xub_StrLen nChar = 0; nChar < nLen; ++nChar )
5116 pStd97Pass[nChar] = sUniPassword.GetChar(nChar);
5118 aCodec97.InitKey( pStd97Pass, pDocId );
5120 // merge the EncryptionData, there should be no conflicts
5121 ::comphelper::SequenceAsHashMap aEncryptionHash( aEncryptionData );
5122 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
5123 aEncryptionHash >> aEncryptionData;
5127 return aEncryptionData;
5130 uno::Sequence< beans::NamedValue > InitStd97Codec( ::msfilter::MSCodec_Std97& rCodec, sal_uInt8 pDocId[16], SfxMedium& rMedium )
5132 uno::Sequence< beans::NamedValue > aEncryptionData;
5133 SFX_ITEMSET_ARG( rMedium.GetItemSet(), pEncryptionData, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False );
5134 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5135 aEncryptionData.realloc( 0 );
5137 if ( !aEncryptionData.getLength() )
5139 String sUniPassword = QueryPasswordForMedium( rMedium );
5141 xub_StrLen nLen = sUniPassword.Len();
5142 if ( nLen <= 15 )
5144 sal_Unicode pPassword[16];
5145 memset( pPassword, 0, sizeof( pPassword ) );
5146 for (xub_StrLen nChar = 0; nChar < nLen; ++nChar )
5147 pPassword[nChar] = sUniPassword.GetChar(nChar);
5149 rCodec.InitKey( pPassword, pDocId );
5150 aEncryptionData = rCodec.GetEncryptionData();
5154 return aEncryptionData;
5158 sal_uLong SwWW8ImplReader::LoadThroughDecryption(SwPaM& rPaM ,WW8Glossary *pGloss)
5160 sal_uLong nErrRet = 0;
5161 if (pGloss)
5162 pWwFib = pGloss->GetFib();
5163 else
5164 pWwFib = new WW8Fib(*pStrm, nWantedVersion);
5166 if (pWwFib->nFibError)
5167 nErrRet = ERR_SWG_READ_ERROR;
5169 SvStorageStreamRef xTableStream, xDataStream;
5171 if (!nErrRet)
5172 nErrRet = SetSubStreams(xTableStream, xDataStream);
5174 utl::TempFile *pTempMain = 0;
5175 utl::TempFile *pTempTable = 0;
5176 utl::TempFile *pTempData = 0;
5177 SvFileStream aDecryptMain;
5178 SvFileStream aDecryptTable;
5179 SvFileStream aDecryptData;
5181 bool bDecrypt = false;
5182 enum {RC4, XOR, Other} eAlgo = Other;
5183 if (pWwFib->fEncrypted && !nErrRet)
5185 if (!pGloss)
5187 bDecrypt = true;
5188 if (8 != pWwFib->nVersion)
5189 eAlgo = XOR;
5190 else
5192 if (pWwFib->nKey != 0)
5193 eAlgo = XOR;
5194 else
5196 pTableStream->Seek(0);
5197 sal_uInt32 nEncType;
5198 *pTableStream >> nEncType;
5199 if (nEncType == 0x10001)
5200 eAlgo = RC4;
5206 if (bDecrypt)
5208 nErrRet = ERRCODE_SVX_WRONGPASS;
5209 SfxMedium* pMedium = mpDocShell->GetMedium();
5211 if ( pMedium )
5213 switch (eAlgo)
5215 default:
5216 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5217 break;
5218 case XOR:
5220 msfilter::MSCodec_XorWord95 aCtx;
5221 uno::Sequence< beans::NamedValue > aEncryptionData = InitXorWord95Codec( aCtx, *pMedium, pWwFib );
5223 // if initialization has failed the EncryptionData should be empty
5224 if ( aEncryptionData.getLength() && aCtx.VerifyKey( pWwFib->nKey, pWwFib->nHash ) )
5226 nErrRet = 0;
5227 pTempMain = MakeTemp(aDecryptMain);
5229 pStrm->Seek(0);
5230 size_t nUnencryptedHdr =
5231 (8 == pWwFib->nVersion) ? 0x44 : 0x34;
5232 sal_uInt8 *pIn = new sal_uInt8[nUnencryptedHdr];
5233 nUnencryptedHdr = pStrm->Read(pIn, nUnencryptedHdr);
5234 aDecryptMain.Write(pIn, nUnencryptedHdr);
5235 delete [] pIn;
5237 DecryptXOR(aCtx, *pStrm, aDecryptMain);
5239 if (!pTableStream || pTableStream == pStrm)
5240 pTableStream = &aDecryptMain;
5241 else
5243 pTempTable = MakeTemp(aDecryptTable);
5244 DecryptXOR(aCtx, *pTableStream, aDecryptTable);
5245 pTableStream = &aDecryptTable;
5248 if (!pDataStream || pDataStream == pStrm)
5249 pDataStream = &aDecryptMain;
5250 else
5252 pTempData = MakeTemp(aDecryptData);
5253 DecryptXOR(aCtx, *pDataStream, aDecryptData);
5254 pDataStream = &aDecryptData;
5257 pMedium->GetItemSet()->ClearItem( SID_PASSWORD );
5258 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
5261 break;
5262 case RC4:
5264 sal_uInt8 aDocId[ 16 ];
5265 sal_uInt8 aSaltData[ 16 ];
5266 sal_uInt8 aSaltHash[ 16 ];
5268 bool bCouldReadHeaders =
5269 checkRead(*pTableStream, aDocId, 16) &&
5270 checkRead(*pTableStream, aSaltData, 16) &&
5271 checkRead(*pTableStream, aSaltHash, 16);
5273 msfilter::MSCodec_Std97 aCtx;
5274 // if initialization has failed the EncryptionData should be empty
5275 uno::Sequence< beans::NamedValue > aEncryptionData;
5276 if (bCouldReadHeaders)
5277 aEncryptionData = InitStd97Codec( aCtx, aDocId, *pMedium );
5278 if ( aEncryptionData.getLength() && aCtx.VerifyKey( aSaltData, aSaltHash ) )
5280 nErrRet = 0;
5282 pTempMain = MakeTemp(aDecryptMain);
5284 pStrm->Seek(0);
5285 sal_Size nUnencryptedHdr = 0x44;
5286 sal_uInt8 *pIn = new sal_uInt8[nUnencryptedHdr];
5287 nUnencryptedHdr = pStrm->Read(pIn, nUnencryptedHdr);
5289 DecryptRC4(aCtx, *pStrm, aDecryptMain);
5291 aDecryptMain.Seek(0);
5292 aDecryptMain.Write(pIn, nUnencryptedHdr);
5293 delete [] pIn;
5296 pTempTable = MakeTemp(aDecryptTable);
5297 DecryptRC4(aCtx, *pTableStream, aDecryptTable);
5298 pTableStream = &aDecryptTable;
5300 if (!pDataStream || pDataStream == pStrm)
5301 pDataStream = &aDecryptMain;
5302 else
5304 pTempData = MakeTemp(aDecryptData);
5305 DecryptRC4(aCtx, *pDataStream, aDecryptData);
5306 pDataStream = &aDecryptData;
5309 pMedium->GetItemSet()->ClearItem( SID_PASSWORD );
5310 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
5313 break;
5317 if (nErrRet == 0)
5319 pStrm = &aDecryptMain;
5321 delete pWwFib;
5322 pWwFib = new WW8Fib(*pStrm, nWantedVersion);
5323 if (pWwFib->nFibError)
5324 nErrRet = ERR_SWG_READ_ERROR;
5328 if (!nErrRet)
5329 nErrRet = CoreLoad(pGloss, *rPaM.GetPoint());
5331 delete pTempMain;
5332 delete pTempTable;
5333 delete pTempData;
5335 if (!pGloss)
5336 delete pWwFib;
5337 return nErrRet;
5340 class outlineeq : public std::unary_function<const SwTxtFmtColl*, bool>
5342 private:
5343 sal_uInt8 mnNum;
5344 public:
5345 outlineeq(sal_uInt8 nNum) : mnNum(nNum) {}
5346 bool operator()(const SwTxtFmtColl *pTest) const
5348 return pTest->IsAssignedToListLevelOfOutlineStyle() && pTest->GetAssignedOutlineStyleLevel() == mnNum; //<-end,zhaojianwei
5352 void SwWW8ImplReader::SetOutLineStyles()
5355 #i3674# & #101291# Load new document and insert document cases.
5357 SwNumRule aOutlineRule(*rDoc.GetOutlineNumRule());
5358 // #i53044,i53213#
5359 // <mpChosenOutlineNumRule> has to be set to point to local variable
5360 // <aOutlineRule>, because its used below to be compared this <&aOutlineRule>.
5361 // But at the end of the method <mpChosenOutlineNumRule> has to be set to
5362 // <rDoc.GetOutlineNumRule()>, because <aOutlineRule> will be destroyed.
5363 mpChosenOutlineNumRule = &aOutlineRule;
5365 sw::ParaStyles aOutLined(sw::util::GetParaStyles(rDoc));
5366 // #i98791# - sorting algorithm adjusted
5367 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined);
5369 typedef sw::ParaStyleIter myParaStyleIter;
5371 If we are inserted into a document then don't clobber existing existing
5372 levels.
5374 sal_uInt16 nFlagsStyleOutlLevel = 0;
5375 if (!mbNewDoc)
5377 // #i70748# - backward iteration needed due to the outline level attribute
5378 sw::ParaStyles::reverse_iterator aEnd = aOutLined.rend();
5379 for ( sw::ParaStyles::reverse_iterator aIter = aOutLined.rbegin(); aIter < aEnd; ++aIter)
5381 if ((*aIter)->IsAssignedToListLevelOfOutlineStyle())
5382 nFlagsStyleOutlLevel |= 1 << (*aIter)->GetAssignedOutlineStyleLevel();//<-end,zhaojianwei
5383 else
5384 break;
5387 else
5390 Only import *one* of the possible multiple outline numbering rules, so
5391 pick the one that affects most styles. If we're not importing a new
5392 document, we got to stick with what is already there.
5394 // use index in text format collection array <vColl>
5395 // as key of the outline numbering map <aRuleMap>
5396 // instead of the memory pointer of the outline numbering rule
5397 // to assure that, if two outline numbering rule affect the same
5398 // count of text formats, always the same outline numbering rule is chosen.
5399 std::map<sal_uInt16, int>aRuleMap;
5400 typedef std::map<sal_uInt16, int>::iterator myIter;
5401 for (sal_uInt16 nI = 0; nI < vColl.size(); ++nI)
5403 SwWW8StyInf& rSI = vColl[ nI ];
5404 if (
5405 (MAXLEVEL > rSI.nOutlineLevel) && rSI.pOutlineNumrule &&
5406 rSI.pFmt
5409 myIter aIter = aRuleMap.find(nI);
5410 if (aIter == aRuleMap.end())
5412 aRuleMap[nI] = 1;
5414 else
5415 ++(aIter->second);
5419 int nMax = 0;
5420 myIter aEnd2 = aRuleMap.end();
5421 for (myIter aIter = aRuleMap.begin(); aIter != aEnd2; ++aIter)
5423 if (aIter->second > nMax)
5425 nMax = aIter->second;
5426 if(aIter->first < vColl.size())
5427 mpChosenOutlineNumRule = vColl[ aIter->first ].pOutlineNumrule;
5428 else
5429 mpChosenOutlineNumRule = 0; //TODO make sure this is what we want
5433 OSL_ENSURE(mpChosenOutlineNumRule, "Impossible");
5434 if (mpChosenOutlineNumRule)
5435 aOutlineRule = *mpChosenOutlineNumRule;
5437 if (mpChosenOutlineNumRule != &aOutlineRule)
5439 // #i70748# - backward iteration needed due to the outline level attribute
5440 sw::ParaStyles::reverse_iterator aEnd = aOutLined.rend();
5441 for ( sw::ParaStyles::reverse_iterator aIter = aOutLined.rbegin(); aIter < aEnd; ++aIter)
5443 if((*aIter)->IsAssignedToListLevelOfOutlineStyle())
5444 (*aIter)->DeleteAssignmentToListLevelOfOutlineStyle(); //<-end
5446 else
5447 break;
5452 sal_uInt16 nOldFlags = nFlagsStyleOutlLevel;
5454 for (sal_uInt16 nI = 0; nI < vColl.size(); ++nI)
5456 SwWW8StyInf& rSI = vColl[nI];
5458 if (rSI.IsOutlineNumbered())
5460 sal_uInt16 nAktFlags = 1 << rSI.nOutlineLevel;
5461 if (
5462 (nAktFlags & nFlagsStyleOutlLevel) ||
5463 (rSI.pOutlineNumrule != mpChosenOutlineNumRule)
5467 If our spot is already taken by something we can't replace
5468 then don't insert and remove our outline level.
5470 rSI.pFmt->SetFmtAttr(
5471 SwNumRuleItem( rSI.pOutlineNumrule->GetName() ) );
5472 ((SwTxtFmtColl*)rSI.pFmt)->DeleteAssignmentToListLevelOfOutlineStyle();//#outline level,zhaojianwei
5474 else
5477 If there is a style already set for this outline
5478 numbering level and its not a style set by us already
5479 then we can remove it outline numbering.
5480 (its one of the default headings in a new document
5481 so we can clobber it)
5482 Of course if we are being inserted into a document that
5483 already has some set we can't do this, thats covered by
5484 the list of level in nFlagsStyleOutlLevel to ignore.
5486 outlineeq aCmp(rSI.nOutlineLevel);
5487 myParaStyleIter aResult = std::find_if(aOutLined.begin(),
5488 aOutLined.end(), aCmp);
5490 myParaStyleIter aEnd = aOutLined.end();
5491 while (aResult != aEnd && aCmp(*aResult))
5493 (*aResult)->DeleteAssignmentToListLevelOfOutlineStyle();
5494 ++aResult;
5498 #i1886#
5499 I believe that when a list is registered onto a winword
5500 style which is an outline numbering style (i.e.
5501 nOutlineLevel is set) that the style of numbering is for
5502 the level is indexed by the *list* level that was
5503 registered on that style, and not the outlinenumbering
5504 level, which is probably a logical sequencing, and not a
5505 physical mapping into the list style reged on that outline
5506 style.
5508 sal_uInt8 nFromLevel = rSI.nListLevel;
5509 sal_uInt8 nToLevel = rSI.nOutlineLevel;
5510 const SwNumFmt& rRule=rSI.pOutlineNumrule->Get(nFromLevel);
5511 aOutlineRule.Set(nToLevel, rRule);
5512 ((SwTxtFmtColl*)rSI.pFmt)->AssignToListLevelOfOutlineStyle(nToLevel); //<-end,zhaojianwei
5513 // If there are more styles on this level ignore them
5514 nFlagsStyleOutlLevel |= nAktFlags;
5518 if (nOldFlags != nFlagsStyleOutlLevel)
5519 rDoc.SetOutlineNumRule(aOutlineRule);
5520 // #i53044,i53213#
5521 if ( mpChosenOutlineNumRule == &aOutlineRule )
5523 mpChosenOutlineNumRule = rDoc.GetOutlineNumRule();
5527 const String* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx)
5529 if (!mpAtnNames && pWwFib->lcbGrpStAtnOwners)
5531 // Authoren bestimmen: steht im TableStream
5532 mpAtnNames = new ::std::vector<String>;
5533 SvStream& rStrm = *pTableStream;
5535 long nOldPos = rStrm.Tell();
5536 rStrm.Seek( pWwFib->fcGrpStAtnOwners );
5538 long nRead = 0, nCount = pWwFib->lcbGrpStAtnOwners;
5539 while (nRead < nCount)
5541 if( bVer67 )
5543 mpAtnNames->push_back(read_uInt8_PascalString(rStrm,
5544 RTL_TEXTENCODING_MS_1252));
5545 nRead += mpAtnNames->rbegin()->Len() + 1; // Laenge + sal_uInt8 Count
5547 else
5549 mpAtnNames->push_back(read_uInt16_PascalString(rStrm));
5550 // UNICode: doppelte Laenge + sal_uInt16 Count
5551 nRead += mpAtnNames->rbegin()->Len() * 2 + 2;
5554 rStrm.Seek( nOldPos );
5557 const String *pRet = 0;
5558 if (mpAtnNames && nIdx < mpAtnNames->size())
5559 pRet = &((*mpAtnNames)[nIdx]);
5560 return pRet;
5563 int SwWW8ImplReader::GetAnnotationIndex(sal_uInt32 nTag)
5565 if (!mpAtnIndexes.get() && pWwFib->lcbSttbfAtnbkmk)
5567 mpAtnIndexes.reset(new std::map<sal_uInt32, int>());
5568 std::vector<String> aStrings;
5569 std::vector<ww::bytes> aEntries;
5570 WW8ReadSTTBF(!bVer67, *pTableStream, pWwFib->fcSttbfAtnbkmk, pWwFib->lcbSttbfAtnbkmk, sizeof(struct WW8_ATNBE), eStructCharSet, aStrings, &aEntries);
5571 for (size_t i = 0; i < aStrings.size() && i < aEntries.size(); ++i)
5573 ww::bytes aEntry = aEntries[i];
5574 WW8_ATNBE* pAtnbeStruct = (WW8_ATNBE*)(&aEntry[0]);
5575 mpAtnIndexes->insert(std::pair<sal_uInt32, int>(SVBT32ToUInt32(pAtnbeStruct->nTag), i));
5578 if (mpAtnIndexes.get())
5580 std::map<sal_uInt32, int>::iterator it = mpAtnIndexes->find(nTag);
5581 if (it != mpAtnIndexes->end())
5582 return it->second;
5584 return -1;
5587 WW8_CP SwWW8ImplReader::GetAnnotationStart(int nIndex)
5589 if (!mpAtnStarts.get() && pWwFib->lcbPlcfAtnbkf)
5590 // A PLCFBKF is a PLC whose data elements are FBKF structures (4 bytes each).
5591 mpAtnStarts.reset(new WW8PLCFspecial(pTableStream, pWwFib->fcPlcfAtnbkf, pWwFib->lcbPlcfAtnbkf, 4));
5593 if (mpAtnStarts.get())
5594 return mpAtnStarts->GetPos(nIndex);
5595 else
5596 return SAL_MAX_INT32;
5599 WW8_CP SwWW8ImplReader::GetAnnotationEnd(int nIndex)
5601 if (!mpAtnEnds.get() && pWwFib->lcbPlcfAtnbkl)
5602 // The Plcfbkl structure is a PLC that contains only CPs and no additional data.
5603 mpAtnEnds.reset(new WW8PLCFspecial(pTableStream, pWwFib->fcPlcfAtnbkl, pWwFib->lcbPlcfAtnbkl, 0));
5605 if (mpAtnEnds.get())
5606 return mpAtnEnds->GetPos(nIndex);
5607 else
5608 return SAL_MAX_INT32;
5611 sal_uLong SwWW8ImplReader::LoadDoc( SwPaM& rPaM,WW8Glossary *pGloss)
5613 sal_uLong nErrRet = 0;
5616 static const sal_Char* aNames[ 13 ] = {
5617 "WinWord/WW", "WinWord/WW8", "WinWord/WWFT",
5618 "WinWord/WWFLX", "WinWord/WWFLY",
5619 "WinWord/WWF",
5620 "WinWord/WWFA0", "WinWord/WWFA1", "WinWord/WWFA2",
5621 "WinWord/WWFB0", "WinWord/WWFB1", "WinWord/WWFB2",
5622 "WinWord/RegardHindiDigits"
5624 sal_uInt32 aVal[ 13 ];
5626 SwFilterOptions aOpt( 13, aNames, aVal );
5628 nIniFlags = aVal[ 0 ];
5629 nIniFlags1= aVal[ 1 ];
5630 // schiebt Flys um x twips nach rechts o. links
5631 nIniFlyDx = aVal[ 3 ];
5632 nIniFlyDy = aVal[ 4 ];
5634 nFieldFlags = aVal[ 5 ];
5635 nFieldTagAlways[0] = aVal[ 6 ];
5636 nFieldTagAlways[1] = aVal[ 7 ];
5637 nFieldTagAlways[2] = aVal[ 8 ];
5638 nFieldTagBad[0] = aVal[ 9 ];
5639 nFieldTagBad[1] = aVal[ 10 ];
5640 nFieldTagBad[2] = aVal[ 11 ];
5641 m_bRegardHindiDigits = aVal[ 12 ] > 0;
5644 sal_uInt16 nMagic(0);
5645 *pStrm >> nMagic;
5647 // beachte: 6 steht fuer "6 ODER 7", 7 steht fuer "NUR 7"
5648 switch (nWantedVersion)
5650 case 6:
5651 case 7:
5652 if (
5653 (0xa5dc != nMagic && 0xa5db != nMagic) &&
5654 (nMagic < 0xa697 || nMagic > 0xa699)
5657 // teste auf eigenen 97-Fake!
5658 if (pStg && 0xa5ec == nMagic)
5660 sal_uLong nCurPos = pStrm->Tell();
5661 if (pStrm->Seek(nCurPos + 22))
5663 sal_uInt32 nfcMin;
5664 *pStrm >> nfcMin;
5665 if (0x300 != nfcMin)
5666 nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
5668 pStrm->Seek( nCurPos );
5670 else
5671 nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
5673 break;
5674 case 8:
5675 if (0xa5ec != nMagic)
5676 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
5677 break;
5678 default:
5679 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
5680 OSL_ENSURE( !this, "Es wurde vergessen, nVersion zu kodieren!" );
5681 break;
5684 if (!nErrRet)
5685 nErrRet = LoadThroughDecryption(rPaM ,pGloss);
5687 rDoc.PropagateOutlineRule();
5689 return nErrRet;
5692 extern "C" SAL_DLLPUBLIC_EXPORT Reader* SAL_CALL ImportDOC()
5694 return new WW8Reader();
5697 sal_uLong WW8Reader::OpenMainStream( SvStorageStreamRef& rRef, sal_uInt16& rBuffSize )
5699 sal_uLong nRet = ERR_SWG_READ_ERROR;
5700 OSL_ENSURE( pStg, "wo ist mein Storage?" );
5701 rRef = pStg->OpenSotStream( OUString("WordDocument"), STREAM_READ | STREAM_SHARE_DENYALL);
5703 if( rRef.Is() )
5705 if( SVSTREAM_OK == rRef->GetError() )
5707 sal_uInt16 nOld = rRef->GetBufferSize();
5708 rRef->SetBufferSize( rBuffSize );
5709 rBuffSize = nOld;
5710 nRet = 0;
5712 else
5713 nRet = rRef->GetError();
5715 return nRet;
5718 sal_uLong WW8Reader::Read(SwDoc &rDoc, const String& rBaseURL, SwPaM &rPam, const String & /* FileName */)
5720 sal_uInt16 nOldBuffSize = 32768;
5721 bool bNew = !bInsertMode; // Neues Doc ( kein Einfuegen )
5724 SvStorageStreamRef refStrm; // damit uns keiner den Stream klaut
5725 SvStream* pIn = pStrm;
5727 sal_uLong nRet = 0;
5728 sal_uInt8 nVersion = 8;
5730 String sFltName = GetFltName();
5731 if( sFltName.EqualsAscii( "WW6" ) )
5733 if (pStrm)
5734 nVersion = 6;
5735 else
5737 OSL_ENSURE(!this, "WinWord 95 Reader-Read ohne Stream");
5738 nRet = ERR_SWG_READ_ERROR;
5741 else
5743 if( sFltName.EqualsAscii( "CWW6" ) )
5744 nVersion = 6;
5745 else if( sFltName.EqualsAscii( "CWW7" ) )
5746 nVersion = 7;
5748 if( pStg )
5750 nRet = OpenMainStream( refStrm, nOldBuffSize );
5751 pIn = &refStrm;
5753 else
5755 OSL_ENSURE(!this, "WinWord 95/97 Reader-Read ohne Storage");
5756 nRet = ERR_SWG_READ_ERROR;
5760 if( !nRet )
5762 if (bNew)
5764 // MIB 27.09.96: Umrandung uns Abstaende aus Frm-Vorlagen entf.
5765 Reader::ResetFrmFmts( rDoc );
5767 SwWW8ImplReader* pRdr = new SwWW8ImplReader(nVersion, pStg, pIn, rDoc,
5768 rBaseURL, bNew);
5771 nRet = pRdr->LoadDoc( rPam );
5773 catch( const std::exception& )
5775 nRet = ERR_WW8_NO_WW8_FILE_ERR;
5777 delete pRdr;
5779 if( refStrm.Is() )
5781 refStrm->SetBufferSize( nOldBuffSize );
5782 refStrm.Clear();
5784 else if (pIn)
5785 pIn->ResetError();
5788 return nRet;
5791 int WW8Reader::GetReaderType()
5793 return SW_STORAGE_READER | SW_STREAM_READER;
5796 sal_Bool WW8Reader::HasGlossaries() const
5798 return true;
5801 sal_Bool WW8Reader::ReadGlossaries(SwTextBlocks& rBlocks, sal_Bool bSaveRelFiles) const
5803 bool bRet=false;
5805 WW8Reader *pThis = const_cast<WW8Reader *>(this);
5807 sal_uInt16 nOldBuffSize = 32768;
5808 SvStorageStreamRef refStrm;
5809 if (!pThis->OpenMainStream(refStrm, nOldBuffSize))
5811 WW8Glossary aGloss( refStrm, 8, pStg );
5812 bRet = aGloss.Load( rBlocks, bSaveRelFiles ? true : false);
5814 return bRet ? true : false;
5817 sal_Bool SwMSDffManager::GetOLEStorageName(long nOLEId, OUString& rStorageName,
5818 SvStorageRef& rSrcStorage, uno::Reference < embed::XStorage >& rDestStorage) const
5820 bool bRet = false;
5822 sal_Int32 nPictureId = 0;
5823 if (rReader.pStg)
5825 // dann holen wir uns mal ueber den TextBox-PLCF die richtigen
5826 // Char Start-/End-Positionen. In dem Bereich sollte dann
5827 // das EinbettenFeld und die entsprechenden Sprms zu finden
5828 // sein. Wir brauchen hier aber nur das Sprm fuer die Picture Id
5829 long nOldPos = rReader.pStrm->Tell();
5831 // #i32596# - consider return value of method
5832 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
5833 // wasn't successful. Thus, continue in this case.
5834 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
5835 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
5836 WW8_CP nStartCp, nEndCp;
5837 if ( rReader.GetTxbxTextSttEndCp(nStartCp, nEndCp,
5838 static_cast<sal_uInt16>((nOLEId >> 16) & 0xFFFF),
5839 static_cast<sal_uInt16>(nOLEId & 0xFFFF)) )
5841 WW8PLCFxSaveAll aSave;
5842 memset( &aSave, 0, sizeof( aSave ) );
5843 rReader.pPlcxMan->SaveAllPLCFx( aSave );
5845 nStartCp += rReader.nDrawCpO;
5846 nEndCp += rReader.nDrawCpO;
5847 WW8PLCFx_Cp_FKP* pChp = rReader.pPlcxMan->GetChpPLCF();
5848 wwSprmParser aSprmParser(rReader.pWwFib->GetFIBVersion());
5849 while (nStartCp <= nEndCp && !nPictureId)
5851 WW8PLCFxDesc aDesc;
5852 pChp->SeekPos( nStartCp );
5853 pChp->GetSprms( &aDesc );
5855 if (aDesc.nSprmsLen && aDesc.pMemPos) // Attribut(e) vorhanden
5857 long nLen = aDesc.nSprmsLen;
5858 const sal_uInt8* pSprm = aDesc.pMemPos;
5860 while (nLen >= 2 && !nPictureId)
5862 sal_uInt16 nId = aSprmParser.GetSprmId(pSprm);
5863 sal_uInt16 nSL = aSprmParser.GetSprmSize(nId, pSprm);
5865 if( nLen < nSL )
5866 break; // nicht mehr genug Bytes uebrig
5868 if( 0x6A03 == nId && 0 < nLen )
5870 nPictureId = SVBT32ToUInt32(pSprm +
5871 aSprmParser.DistanceToData(nId));
5872 bRet = true;
5874 pSprm += nSL;
5875 nLen -= nSL;
5878 nStartCp = aDesc.nEndPos;
5881 rReader.pPlcxMan->RestoreAllPLCFx( aSave );
5884 rReader.pStrm->Seek( nOldPos );
5887 if( bRet )
5889 rStorageName = OUString('_');
5890 rStorageName += OUString::valueOf(nPictureId);
5891 rSrcStorage = rReader.pStg->OpenSotStorage(OUString(
5892 SL::aObjectPool));
5893 if (!rReader.mpDocShell)
5894 bRet=false;
5895 else
5896 rDestStorage = rReader.mpDocShell->GetStorage();
5898 return bRet;
5901 sal_Bool SwMSDffManager::ShapeHasText(sal_uLong, sal_uLong) const
5903 // Zur Zeit des Einlesens einer einzelnen Box, die womoeglich Teil einer
5904 // Gruppe ist, liegen noch nicht genuegend Informationen vor, um
5905 // entscheiden zu koennen, ob wir sie nicht doch als Textfeld benoetigen.
5906 // Also vorsichtshalber mal alle umwandeln:
5907 return true;
5910 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl) const
5912 if (nLvl)
5913 --nLvl;
5914 // #i60827#
5915 // check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
5916 if ( sal::static_int_cast< sal_Int32>(nLvl) >= sal::static_int_cast< sal_Int32>(maApos.size()) )
5918 return false;
5920 mycApoIter aIter = std::find(maApos.begin() + nLvl, maApos.end(), true);
5921 if (aIter != maApos.end())
5922 return true;
5923 else
5924 return false;
5927 bool SwWW8ImplReader::InEqualApo(int nLvl) const
5929 //If we are in a table, see if an apo was inserted at the level below
5930 //the table.
5931 if (nLvl)
5932 --nLvl;
5933 if (nLvl < 0 || static_cast<size_t>(nLvl) >= maApos.size())
5934 return false;
5935 return maApos[nLvl];
5938 namespace sw
5940 namespace hack
5942 Position::Position(const SwPosition &rPos)
5943 : maPtNode(rPos.nNode), mnPtCntnt(rPos.nContent.GetIndex())
5947 Position::Position(const Position &rPos)
5948 : maPtNode(rPos.maPtNode), mnPtCntnt(rPos.mnPtCntnt)
5952 Position::operator SwPosition() const
5954 SwPosition aRet(maPtNode);
5955 aRet.nContent.Assign(maPtNode.GetNode().GetCntntNode(), mnPtCntnt);
5956 return aRet;
5961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */