build fix
[LibreOffice.git] / sw / source / filter / ww8 / ww8par.cxx
blob809ff89a01d93908729d6dedbb012d1ae6bc5be3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <sal/config.h>
24 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <i18nlangtag/languagetag.hxx>
28 #include <unotools/configmgr.hxx>
29 #include <unotools/ucbstreamhelper.hxx>
30 #include <rtl/random.h>
31 #include <rtl/ustring.hxx>
32 #include <rtl/ustrbuf.hxx>
34 #include <sfx2/docinf.hxx>
35 #include <sfx2/request.hxx>
36 #include <sfx2/frame.hxx>
37 #include <tools/urlobj.hxx>
38 #include <unotools/tempfile.hxx>
40 #include <comphelper/docpasswordrequest.hxx>
41 #include <comphelper/string.hxx>
43 #include <editeng/brushitem.hxx>
44 #include <editeng/tstpitem.hxx>
45 #include <editeng/ulspitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/opaqitem.hxx>
48 #include <editeng/charhiddenitem.hxx>
49 #include <editeng/fontitem.hxx>
50 #include <svx/unoapi.hxx>
51 #include <svx/svdoole2.hxx>
52 #include <svx/svdoashp.hxx>
53 #include <svx/svxerr.hxx>
54 #include <filter/msfilter/mscodec.hxx>
55 #include <svx/svdmodel.hxx>
56 #include <svx/xflclit.hxx>
58 #include <unotools/fltrcfg.hxx>
59 #include <fmtfld.hxx>
60 #include <fmturl.hxx>
61 #include <fmtinfmt.hxx>
62 #include <reffld.hxx>
63 #include <fmthdft.hxx>
64 #include <fmtcntnt.hxx>
65 #include <fmtcnct.hxx>
66 #include <fmtanchr.hxx>
67 #include <fmtpdsc.hxx>
68 #include <ftninfo.hxx>
69 #include <fmtftn.hxx>
70 #include <txtftn.hxx>
71 #include <ndtxt.hxx>
72 #include <pagedesc.hxx>
73 #include <paratr.hxx>
74 #include <fmtclbl.hxx>
75 #include <section.hxx>
76 #include <docsh.hxx>
77 #include <IDocumentFieldsAccess.hxx>
78 #include <IDocumentLayoutAccess.hxx>
79 #include <IDocumentStylePoolAccess.hxx>
80 #include <IDocumentExternalData.hxx>
81 #include <docufld.hxx>
82 #include <swfltopt.hxx>
83 #include <viewsh.hxx>
84 #include <viewopt.hxx>
85 #include <shellres.hxx>
86 #include <mdiexp.hxx>
87 #include <statstr.hrc>
88 #include <swerror.h>
89 #include <swtable.hxx>
90 #include <fchrfmt.hxx>
91 #include <charfmt.hxx>
92 #include <unocrsr.hxx>
93 #include <IDocumentSettingAccess.hxx>
94 #include <sprmids.hxx>
96 #include <fltini.hxx>
98 #include "writerwordglue.hxx"
100 #include "ndgrf.hxx"
101 #include <editeng/editids.hrc>
102 #include <txtflcnt.hxx>
103 #include <fmtflcnt.hxx>
104 #include <txatbase.hxx>
106 #include "ww8par2.hxx"
108 #include <com/sun/star/beans/PropertyAttribute.hpp>
109 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
110 #include <com/sun/star/document/XViewDataSupplier.hpp>
111 #include <com/sun/star/document/IndexedPropertyValues.hpp>
112 #include <svl/itemiter.hxx>
114 #include <comphelper/processfactory.hxx>
115 #include <basic/basmgr.hxx>
117 #include "ww8toolbar.hxx"
118 #include <osl/file.hxx>
120 #include <breakit.hxx>
122 #if OSL_DEBUG_LEVEL > 1
123 #include <iostream>
124 #include <dbgoutsw.hxx>
125 #endif
127 #include <svx/hlnkitem.hxx>
128 #include "swdll.hxx"
129 #include "WW8Sttbf.hxx"
130 #include "WW8FibData.hxx"
131 #include <unordered_set>
132 #include <memory>
134 using namespace ::com::sun::star;
135 using namespace sw::util;
136 using namespace sw::types;
137 using namespace nsHdFtFlags;
139 #include <com/sun/star/i18n/ScriptType.hpp>
140 #include <unotools/pathoptions.hxx>
141 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
143 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
144 #include <comphelper/sequenceashashmap.hxx>
145 #include <oox/ole/vbaproject.hxx>
146 #include <oox/ole/olestorage.hxx>
147 #include <comphelper/storagehelper.hxx>
148 #include <sfx2/DocumentMetadataAccess.hxx>
150 //#define VT_EMPTY 0
151 //#define VT_I4 3
152 //#define VT_LPSTR 30
153 //#define VT_LPWSTR 31
154 //#define VT_BLOB 65
155 //#define VT_TYPEMASK 0xFFF
156 /** Expands to a pointer after the last element of a STATIC data array (like STL end()). */
157 //#define STATIC_TABLE_END( array ) ((array)+STATIC_TABLE_SIZE(array))
158 /** Expands to the size of a STATIC data array. */
159 //#define STATIC_TABLE_SIZE( array ) (sizeof(array)/sizeof(*(array)))
161 SwMacroInfo* GetMacroInfo( SdrObject* pObj, bool bCreate ) // static
163 if ( pObj )
165 sal_uInt16 nCount = pObj->GetUserDataCount();
166 for( sal_uInt16 i = 0; i < nCount; i++ )
168 SdrObjUserData* pData = pObj->GetUserData( i );
169 if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw
170 && pData->GetId() == SW_UD_IMAPDATA)
172 return dynamic_cast<SwMacroInfo*>(pData);
175 if ( bCreate )
177 SwMacroInfo* pData = new SwMacroInfo;
178 pObj->AppendUserData(pData);
179 return pData;
183 return nullptr;
186 void lclGetAbsPath(OUString& rPath, sal_uInt16 nLevel, SwDocShell* pDocShell)
188 OUString aTmpStr;
189 while( nLevel )
191 aTmpStr += "../";
192 --nLevel;
194 if (!aTmpStr.isEmpty())
195 aTmpStr += rPath;
196 else
197 aTmpStr = rPath;
199 if (!aTmpStr.isEmpty())
201 bool bWasAbs = false;
202 rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr, bWasAbs ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
203 // full path as stored in SvxURLField must be encoded
207 void lclIgnoreString32( SvMemoryStream& rStrm, bool b16Bit )
209 sal_uInt32 nChars(0);
210 rStrm.ReadUInt32( nChars );
211 if( b16Bit )
212 nChars *= 2;
213 rStrm.SeekRel( nChars );
216 OUString SwWW8ImplReader::ReadRawUniString(SvMemoryStream& rStrm, sal_uInt16 nChars, bool b16Bit)
218 // Fixed-size characters
219 const sal_uInt8 WW8_NUL_C = '\x00'; /// NUL chararcter.
220 const sal_uInt16 WW8_NUL = WW8_NUL_C; /// NUL chararcter (unicode).
221 sal_Unicode mcNulSubst = '\0';
223 sal_uInt16 nCharsLeft = nChars;
224 sal_Unicode* pcBuffer = new sal_Unicode[ nCharsLeft + 1 ];
226 sal_Unicode* pcUniChar = pcBuffer;
227 sal_Unicode* pcEndChar = pcBuffer + nCharsLeft;
229 if( b16Bit )
231 sal_uInt16 nReadChar;
232 for( ; (pcUniChar < pcEndChar); ++pcUniChar )
234 rStrm.ReadUInt16( nReadChar );
235 (*pcUniChar) = (nReadChar == WW8_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
238 else
240 sal_uInt8 nReadChar;
241 for( ; (pcUniChar < pcEndChar); ++pcUniChar )
243 rStrm.ReadUChar( nReadChar ) ;
244 (*pcUniChar) = (nReadChar == WW8_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
248 *pcEndChar = '\0';
249 OUString aRet(pcBuffer);
250 delete[] pcBuffer;
251 return aRet;
254 void lclAppendString32(OUString& rString, SvMemoryStream& rStrm, sal_uInt32 nChars, bool b16Bit)
256 sal_uInt16 nReadChars = ulimit_cast< sal_uInt16 >( nChars );
257 OUString urlStr = SwWW8ImplReader::ReadRawUniString( rStrm, nReadChars, b16Bit );
258 rString += urlStr;
261 void lclAppendString32(OUString& rString, SvMemoryStream& rStrm, bool b16Bit)
263 sal_uInt32 nValue(0);
264 rStrm.ReadUInt32( nValue );
265 lclAppendString32(rString, rStrm, nValue, b16Bit);
268 void SwWW8ImplReader::ReadEmbeddedData( SvMemoryStream& rStrm, SwDocShell* pDocShell, struct HyperLinksTable& hlStr)
270 // (0x01B8) HLINK
271 // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
272 const sal_uInt32 WW8_HLINK_BODY = 0x00000001; /// Contains file link or URL.
273 const sal_uInt32 WW8_HLINK_ABS = 0x00000002; /// Absolute path.
274 const sal_uInt32 WW8_HLINK_DESCR = 0x00000014; /// Description.
275 const sal_uInt32 WW8_HLINK_MARK = 0x00000008; /// Text mark.
276 const sal_uInt32 WW8_HLINK_FRAME = 0x00000080; /// Target frame.
277 const sal_uInt32 WW8_HLINK_UNC = 0x00000100; /// UNC path.
279 //sal_uInt8 maGuidStdLink[ 16 ] ={
280 // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
282 sal_uInt8 aGuidUrlMoniker[ 16 ] = {
283 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
285 sal_uInt8 aGuidFileMoniker[ 16 ] = {
286 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
288 sal_uInt8 aGuid[16];
289 sal_uInt32 nFlags(0);
291 rStrm.ReadBytes(aGuid, 16);
292 rStrm.SeekRel( 4 );
293 rStrm.ReadUInt32( nFlags );
295 sal_uInt16 nLevel = 0; // counter for level to climb down in path
296 std::unique_ptr< OUString > xLongName; // link / file name
297 std::unique_ptr< OUString > xShortName; // 8.3-representation of file name
298 std::unique_ptr< OUString > xTextMark; // text mark
300 // description (ignore)
301 if( ::get_flag( nFlags, WW8_HLINK_DESCR ) )
302 lclIgnoreString32( rStrm, true );
304 // target frame
305 if( ::get_flag( nFlags, WW8_HLINK_FRAME ) )
307 OUString sFrameName;
308 lclAppendString32(sFrameName, rStrm, true);
309 hlStr.tarFrame = sFrameName;
312 // UNC path
313 if( ::get_flag( nFlags, WW8_HLINK_UNC ) )
315 xLongName.reset( new OUString );
316 lclAppendString32( *xLongName, rStrm, true );
317 lclGetAbsPath( *xLongName, 0 , pDocShell);
319 // file link or URL
320 else if( ::get_flag( nFlags, WW8_HLINK_BODY ) )
322 rStrm.ReadBytes(aGuid, 16);
324 if( (memcmp(aGuid, aGuidFileMoniker, 16) == 0) )
326 rStrm.ReadUInt16( nLevel );
327 xShortName.reset( new OUString );
328 lclAppendString32( *xShortName,rStrm, false );
329 rStrm.SeekRel( 24 );
331 sal_uInt32 nStrLen(0);
332 rStrm.ReadUInt32( nStrLen );
333 if( nStrLen )
335 nStrLen = 0;
336 rStrm.ReadUInt32( nStrLen );
337 nStrLen /= 2;
338 rStrm.SeekRel( 2 );
339 xLongName.reset( new OUString );
340 lclAppendString32( *xLongName, rStrm,nStrLen, true );
341 lclGetAbsPath( *xLongName, nLevel, pDocShell);
343 else
344 lclGetAbsPath( *xShortName, nLevel, pDocShell);
346 else if( (memcmp(aGuid, aGuidUrlMoniker, 16) == 0) )
348 sal_uInt32 nStrLen(0);
349 rStrm.ReadUInt32( nStrLen );
350 nStrLen /= 2;
351 xLongName.reset( new OUString );
352 lclAppendString32( *xLongName,rStrm, nStrLen, true );
353 if( !::get_flag( nFlags, WW8_HLINK_ABS ) )
354 lclGetAbsPath( *xLongName, 0 ,pDocShell);
356 else
358 SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID");
362 // text mark
363 if( ::get_flag( nFlags, WW8_HLINK_MARK ) )
365 xTextMark.reset( new OUString );
366 lclAppendString32( *xTextMark, rStrm, true );
369 if( !xLongName.get() && xShortName.get() )
371 xLongName.reset( new OUString );
372 *xLongName = xLongName->concat(*xShortName);
374 else if( !xLongName.get() && xTextMark.get() )
375 xLongName.reset( new OUString );
377 if( xLongName.get() )
379 if( xTextMark.get() )
381 if (xLongName->isEmpty())
382 *xTextMark = xTextMark->replace('!', '.');
383 *xLongName = xLongName->concat("#");
384 *xLongName = xLongName->concat(*xTextMark);
386 hlStr.hLinkAddr = *xLongName;
390 class BasicProjImportHelper
392 SwDocShell& mrDocShell;
393 uno::Reference< uno::XComponentContext > mxCtx;
394 public:
395 explicit BasicProjImportHelper( SwDocShell& rShell ) : mrDocShell( rShell )
397 mxCtx = comphelper::getProcessComponentContext();
399 bool import( const uno::Reference< io::XInputStream >& rxIn );
400 OUString getProjectName();
403 bool BasicProjImportHelper::import( const uno::Reference< io::XInputStream >& rxIn )
405 bool bRet = false;
408 oox::ole::OleStorage root( mxCtx, rxIn, false );
409 oox::StorageRef vbaStg = root.openSubStorage( "Macros" , false );
410 if ( vbaStg.get() )
412 oox::ole::VbaProject aVbaPrj( mxCtx, mrDocShell.GetModel(), OUString("Writer") );
413 bRet = aVbaPrj.importVbaProject( *vbaStg );
416 catch( const uno::Exception& )
418 bRet = false;
420 return bRet;
423 OUString BasicProjImportHelper::getProjectName()
425 OUString sProjName( "Standard" );
426 uno::Reference< beans::XPropertySet > xProps( mrDocShell.GetModel(), uno::UNO_QUERY );
427 if ( xProps.is() )
431 uno::Reference< script::vba::XVBACompatibility > xVBA( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
432 sProjName = xVBA->getProjectName();
435 catch( const uno::Exception& )
439 return sProjName;
442 class Sttb : public TBBase
444 struct SBBItem
446 sal_uInt16 cchData;
447 OUString data;
448 SBBItem() : cchData(0){}
450 sal_uInt16 fExtend;
451 sal_uInt16 cData;
452 sal_uInt16 cbExtra;
454 std::vector< SBBItem > dataItems;
456 Sttb(Sttb const&) = delete;
457 Sttb& operator=(Sttb const&) = delete;
459 public:
460 Sttb();
461 virtual ~Sttb() override;
462 bool Read(SvStream &rS) override;
463 #if OSL_DEBUG_LEVEL > 1
464 virtual void Print( FILE* fp ) override;
465 #endif
466 OUString getStringAtIndex( sal_uInt32 );
469 Sttb::Sttb()
470 : fExtend(0)
471 , cData(0)
472 , cbExtra(0)
476 Sttb::~Sttb()
480 bool Sttb::Read( SvStream& rS )
482 SAL_INFO("sw.ww8", "stream pos " << rS.Tell());
483 nOffSet = rS.Tell();
484 rS.ReadUInt16( fExtend ).ReadUInt16( cData ).ReadUInt16( cbExtra );
485 if ( cData )
487 //if they are all going to be empty strings, how many could there be
488 const size_t nMaxPossibleRecords = rS.remainingSize() / sizeof(sal_uInt16);
489 if (cData > nMaxPossibleRecords)
490 return false;
491 for ( sal_Int32 index = 0; index < cData; ++index )
493 SBBItem aItem;
494 rS.ReadUInt16( aItem.cchData );
495 aItem.data = read_uInt16s_ToOUString(rS, aItem.cchData);
496 dataItems.push_back( aItem );
499 return true;
502 #if OSL_DEBUG_LEVEL > 1
503 void Sttb::Print( FILE* fp )
505 fprintf( fp, "[ 0x%" SAL_PRIxUINT32 " ] Sttb - dump\n", nOffSet);
506 fprintf( fp, " fExtend 0x%x [expected 0xFFFF ]\n", fExtend );
507 fprintf( fp, " cData no. or string data items %d (0x%x)\n", cData, cData );
509 if ( cData )
511 for (sal_uInt16 index = 0; index < cData; ++index)
513 if (index >= dataItems.size())
515 fprintf(fp, " Sttb truncated at entry %d(0x%x)\n", static_cast< int >( index ), static_cast< unsigned int >( index ));
516 break;
518 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() );
522 #endif
524 OUString
525 Sttb::getStringAtIndex( sal_uInt32 index )
527 OUString aRet;
528 if ( index < dataItems.size() )
529 aRet = dataItems[ index ].data;
530 return aRet;
534 SwMSDffManager::SwMSDffManager( SwWW8ImplReader& rRdr, bool bSkipImages )
535 : SvxMSDffManager(*rRdr.m_pTableStream, rRdr.GetBaseURL(), rRdr.m_pWwFib->m_fcDggInfo,
536 rRdr.m_pDataStream, nullptr, 0, COL_WHITE, rRdr.m_pStrm, bSkipImages),
537 rReader(rRdr), pFallbackStream(nullptr)
539 SetSvxMSDffSettings( GetSvxMSDffSettings() );
540 nSvxMSDffOLEConvFlags = SwMSDffManager::GetFilterFlags();
543 sal_uInt32 SwMSDffManager::GetFilterFlags()
545 sal_uInt32 nFlags(0);
546 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
547 if (rOpt.IsMathType2Math())
548 nFlags |= OLE_MATHTYPE_2_STARMATH;
549 if (rOpt.IsExcel2Calc())
550 nFlags |= OLE_EXCEL_2_STARCALC;
551 if (rOpt.IsPowerPoint2Impress())
552 nFlags |= OLE_POWERPOINT_2_STARIMPRESS;
553 if (rOpt.IsWinWord2Writer())
554 nFlags |= OLE_WINWORD_2_STARWRITER;
555 return nFlags;
559 * I would like to override the default OLE importing to add a test
560 * and conversion of OCX controls from their native OLE type into our
561 * native nonOLE Form Control Objects.
563 // #i32596# - consider new parameter <_nCalledByGroup>
564 SdrObject* SwMSDffManager::ImportOLE( long nOLEId,
565 const Graphic& rGrf,
566 const Rectangle& rBoundRect,
567 const Rectangle& rVisArea,
568 const int _nCalledByGroup,
569 sal_Int64 nAspect ) const
571 // #i32596# - no import of OLE object, if it's inside a group.
572 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
573 // if drawing OLE objects are allowed in Writer.
574 if ( _nCalledByGroup > 0 )
576 return nullptr;
579 SdrObject* pRet = nullptr;
580 OUString sStorageName;
581 tools::SvRef<SotStorage> xSrcStg;
582 uno::Reference < embed::XStorage > xDstStg;
583 if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
585 tools::SvRef<SotStorage> xSrc = xSrcStg->OpenSotStorage( sStorageName );
586 OSL_ENSURE(rReader.m_pFormImpl, "No Form Implementation!");
587 css::uno::Reference< css::drawing::XShape > xShape;
588 if ( (!(rReader.m_bIsHeader || rReader.m_bIsFooter)) &&
589 rReader.m_pFormImpl->ReadOCXStream(xSrc,&xShape,true))
591 pRet = GetSdrObjectFromXShape(xShape);
593 else
595 ErrCode nError = ERRCODE_NONE;
596 pRet = CreateSdrOLEFromStorage( sStorageName, xSrcStg, xDstStg,
597 rGrf, rBoundRect, rVisArea, pStData, nError,
598 nSvxMSDffOLEConvFlags, nAspect, rReader.GetBaseURL());
601 return pRet;
604 void SwMSDffManager::DisableFallbackStream()
606 OSL_ENSURE(!pFallbackStream,
607 "if you're recursive, you're broken");
608 pFallbackStream = pStData2;
609 aOldEscherBlipCache = aEscherBlipCache;
610 aEscherBlipCache.clear();
611 pStData2 = nullptr;
614 void SwMSDffManager::EnableFallbackStream()
616 pStData2 = pFallbackStream;
617 aEscherBlipCache = aOldEscherBlipCache;
618 aOldEscherBlipCache.clear();
619 pFallbackStream = nullptr;
622 sal_uInt16 SwWW8ImplReader::GetToggleAttrFlags() const
624 return m_pCtrlStck ? m_pCtrlStck->GetToggleAttrFlags() : 0;
627 sal_uInt16 SwWW8ImplReader::GetToggleBiDiAttrFlags() const
629 return m_pCtrlStck ? m_pCtrlStck->GetToggleBiDiAttrFlags() : 0;
632 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags)
634 if (m_pCtrlStck)
635 m_pCtrlStck->SetToggleAttrFlags(nFlags);
638 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags)
640 if (m_pCtrlStck)
641 m_pCtrlStck->SetToggleBiDiAttrFlags(nFlags);
644 SdrObject* SwMSDffManager::ProcessObj(SvStream& rSt,
645 DffObjData& rObjData,
646 void* pData,
647 Rectangle& rTextRect,
648 SdrObject* pObj
651 if( !rTextRect.IsEmpty() )
653 SvxMSDffImportData& rImportData = *static_cast<SvxMSDffImportData*>(pData);
654 SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec;
656 // fill Import Record with data
657 pImpRec->nShapeId = rObjData.nShapeId;
658 pImpRec->eShapeType = rObjData.eShapeType;
660 rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
661 DFF_msofbtClientAnchor,
662 SEEK_FROM_CURRENT_AND_RESTART );
663 if( rObjData.bClientAnchor )
664 ProcessClientAnchor( rSt,
665 maShapeRecords.Current()->nRecLen,
666 pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
668 rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
669 DFF_msofbtClientData,
670 SEEK_FROM_CURRENT_AND_RESTART );
671 if( rObjData.bClientData )
672 ProcessClientData( rSt,
673 maShapeRecords.Current()->nRecLen,
674 pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
676 // process user (== Winword) defined parameters in 0xF122 record
677 // #i84783# - set special value to determine, if property is provided or not.
678 pImpRec->nLayoutInTableCell = 0xFFFFFFFF;
680 if( maShapeRecords.SeekToContent( rSt,
681 DFF_msofbtUDefProp,
682 SEEK_FROM_CURRENT_AND_RESTART )
683 && maShapeRecords.Current()->nRecLen )
685 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
686 auto nAvailableBytes = rSt.remainingSize();
687 if (nBytesLeft > nAvailableBytes)
689 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft << " bytes, but only " << nAvailableBytes << " available");
690 nBytesLeft = nAvailableBytes;
692 while( 5 < nBytesLeft )
694 sal_uInt16 nPID(0);
695 rSt.ReadUInt16(nPID);
696 sal_uInt32 nUDData(0);
697 rSt.ReadUInt32(nUDData);
698 if (!rSt.good())
699 break;
700 switch (nPID)
702 case 0x038F: pImpRec->nXAlign = nUDData; break;
703 case 0x0390:
704 delete pImpRec->pXRelTo;
705 pImpRec->pXRelTo = new sal_uInt32;
706 *(pImpRec->pXRelTo) = nUDData;
707 break;
708 case 0x0391: pImpRec->nYAlign = nUDData; break;
709 case 0x0392:
710 delete pImpRec->pYRelTo;
711 pImpRec->pYRelTo = new sal_uInt32;
712 *(pImpRec->pYRelTo) = nUDData;
713 break;
714 case 0x03BF: pImpRec->nLayoutInTableCell = nUDData; break;
715 case 0x0393:
716 // This seems to correspond to o:hrpct from .docx (even including
717 // the difference that it's in 0.1% even though the .docx spec
718 // says it's in 1%).
719 pImpRec->relativeHorizontalWidth = nUDData;
720 break;
721 case 0x0394:
722 // And this is really just a guess, but a mere presence of this
723 // flag makes a horizontal rule be as wide as the page (unless
724 // overridden by something), so it probably matches o:hr from .docx.
725 pImpRec->isHorizontalRule = true;
726 break;
728 nBytesLeft -= 6;
732 // Text Frame also Title or Outline
733 sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
734 if( nTextId )
736 SfxItemSet aSet( pSdrModel->GetItemPool() );
738 // Originally anything that as a mso_sptTextBox was created as a
739 // textbox, this was changed to be created as a simple
740 // rect to keep impress happy. For the rest of us we'd like to turn
741 // it back into a textbox again.
742 bool bIsSimpleDrawingTextBox = (pImpRec->eShapeType == mso_sptTextBox);
743 if (!bIsSimpleDrawingTextBox)
745 // Either
746 // a) it's a simple text object or
747 // b) it's a rectangle with text and square wrapping.
748 bIsSimpleDrawingTextBox =
750 (pImpRec->eShapeType == mso_sptTextSimple) ||
752 (pImpRec->eShapeType == mso_sptRectangle)
753 && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
758 // Distance of Textbox to its surrounding Autoshape
759 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L);
760 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L );
761 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L );
762 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L );
764 ScaleEmu( nTextLeft );
765 ScaleEmu( nTextRight );
766 ScaleEmu( nTextTop );
767 ScaleEmu( nTextBottom );
769 sal_Int32 nTextRotationAngle=0;
770 bool bVerticalText = false;
771 if ( IsProperty( DFF_Prop_txflTextFlow ) )
773 MSO_TextFlow eTextFlow = (MSO_TextFlow)(GetPropertyValue(
774 DFF_Prop_txflTextFlow, 0) & 0xFFFF);
775 switch( eTextFlow )
777 case mso_txflBtoT:
778 nTextRotationAngle = 9000;
779 break;
780 case mso_txflVertN:
781 case mso_txflTtoBN:
782 nTextRotationAngle = 27000;
783 break;
784 case mso_txflTtoBA:
785 bVerticalText = true;
786 break;
787 case mso_txflHorzA:
788 bVerticalText = true;
789 nTextRotationAngle = 9000;
790 break;
791 case mso_txflHorzN:
792 default :
793 break;
797 if (nTextRotationAngle)
799 if (nTextRotationAngle == 9000)
801 long nWidth = rTextRect.GetWidth();
802 rTextRect.Right() = rTextRect.Left() + rTextRect.GetHeight();
803 rTextRect.Bottom() = rTextRect.Top() + nWidth;
805 sal_Int32 nOldTextLeft = nTextLeft;
806 sal_Int32 nOldTextRight = nTextRight;
807 sal_Int32 nOldTextTop = nTextTop;
808 sal_Int32 nOldTextBottom = nTextBottom;
810 nTextLeft = nOldTextBottom;
811 nTextRight = nOldTextTop;
812 nTextTop = nOldTextLeft;
813 nTextBottom = nOldTextRight;
815 else if (nTextRotationAngle == 27000)
817 long nWidth = rTextRect.GetWidth();
818 rTextRect.Right() = rTextRect.Left() + rTextRect.GetHeight();
819 rTextRect.Bottom() = rTextRect.Top() + nWidth;
821 sal_Int32 nOldTextLeft = nTextLeft;
822 sal_Int32 nOldTextRight = nTextRight;
823 sal_Int32 nOldTextTop = nTextTop;
824 sal_Int32 nOldTextBottom = nTextBottom;
826 nTextLeft = nOldTextTop;
827 nTextRight = nOldTextBottom;
828 nTextTop = nOldTextRight;
829 nTextBottom = nOldTextLeft;
833 if (bIsSimpleDrawingTextBox)
835 SdrObject::Free( pObj );
836 pObj = new SdrRectObj(OBJ_TEXT, rTextRect);
839 // The vertical paragraph justification are contained within the
840 // BoundRect so calculate it here
841 Rectangle aNewRect(rTextRect);
842 aNewRect.Bottom() -= nTextTop + nTextBottom;
843 aNewRect.Right() -= nTextLeft + nTextRight;
845 // Only if it's a simple Textbox, Writer can replace the Object
846 // with a Frame, else
847 if( bIsSimpleDrawingTextBox )
849 std::shared_ptr<SvxMSDffShapeInfo> const xTmpRec(
850 new SvxMSDffShapeInfo(0, pImpRec->nShapeId));
852 SvxMSDffShapeInfos_ById::const_iterator const it =
853 GetShapeInfos()->find(xTmpRec);
854 if (it != GetShapeInfos()->end())
856 SvxMSDffShapeInfo& rInfo = **it;
857 pImpRec->bReplaceByFly = rInfo.bReplaceByFly;
861 if( bIsSimpleDrawingTextBox )
862 ApplyAttributes( rSt, aSet, rObjData );
864 if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
866 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
867 aSet.Put( makeSdrTextMinFrameHeightItem(
868 aNewRect.Bottom() - aNewRect.Top() ) );
869 aSet.Put( makeSdrTextMinFrameWidthItem(
870 aNewRect.Right() - aNewRect.Left() ) );
872 else
874 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
875 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
878 switch ( (MSO_WrapMode)
879 GetPropertyValue( DFF_Prop_WrapText, mso_wrapSquare ) )
881 case mso_wrapNone :
882 aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
883 pImpRec->bAutoWidth = true;
884 break;
885 case mso_wrapByPoints :
886 aSet.Put( makeSdrTextContourFrameItem( true ) );
887 break;
888 default:
892 // Set distances on Textbox's margins
893 aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
894 aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
895 aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
896 aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
897 pImpRec->nDxTextLeft = nTextLeft;
898 pImpRec->nDyTextTop = nTextTop;
899 pImpRec->nDxTextRight = nTextRight;
900 pImpRec->nDyTextBottom = nTextBottom;
902 // Taking the correct default (which is mso_anchorTop)
903 sal_uInt32 eTextAnchor =
904 GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
906 SdrTextVertAdjust eTVA = bVerticalText
907 ? SDRTEXTVERTADJUST_BLOCK
908 : SDRTEXTVERTADJUST_CENTER;
909 SdrTextHorzAdjust eTHA = bVerticalText
910 ? SDRTEXTHORZADJUST_CENTER
911 : SDRTEXTHORZADJUST_BLOCK;
913 switch( eTextAnchor )
915 case mso_anchorTop:
917 if ( bVerticalText )
918 eTHA = SDRTEXTHORZADJUST_RIGHT;
919 else
920 eTVA = SDRTEXTVERTADJUST_TOP;
922 break;
923 case mso_anchorTopCentered:
925 if ( bVerticalText )
926 eTHA = SDRTEXTHORZADJUST_RIGHT;
927 else
928 eTVA = SDRTEXTVERTADJUST_TOP;
930 break;
931 case mso_anchorMiddle:
932 break;
933 case mso_anchorMiddleCentered:
934 break;
935 case mso_anchorBottom:
937 if ( bVerticalText )
938 eTHA = SDRTEXTHORZADJUST_LEFT;
939 else
940 eTVA = SDRTEXTVERTADJUST_BOTTOM;
942 break;
943 case mso_anchorBottomCentered:
945 if ( bVerticalText )
946 eTHA = SDRTEXTHORZADJUST_LEFT;
947 else
948 eTVA = SDRTEXTVERTADJUST_BOTTOM;
950 break;
951 default:
955 aSet.Put( SdrTextVertAdjustItem( eTVA ) );
956 aSet.Put( SdrTextHorzAdjustItem( eTHA ) );
958 if (pObj != nullptr)
960 pObj->SetMergedItemSet(aSet);
961 pObj->SetModel(pSdrModel);
963 if (bVerticalText)
965 SdrTextObj *pTextObj = dynamic_cast< SdrTextObj* >(pObj);
966 if (pTextObj)
967 pTextObj->SetVerticalWriting(true);
970 if ( bIsSimpleDrawingTextBox )
972 if ( nTextRotationAngle )
974 long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
975 rTextRect.GetWidth() : rTextRect.GetHeight();
976 nMinWH /= 2;
977 Point aPivot(rTextRect.TopLeft());
978 aPivot.X() += nMinWH;
979 aPivot.Y() += nMinWH;
980 double a = nTextRotationAngle * nPi180;
981 pObj->NbcRotate(aPivot, nTextRotationAngle, sin(a), cos(a));
985 if ( ( ( rObjData.nSpFlags & SP_FFLIPV ) || mnFix16Angle || nTextRotationAngle ) && dynamic_cast< SdrObjCustomShape* >( pObj ) )
987 SdrObjCustomShape* pCustomShape = dynamic_cast< SdrObjCustomShape* >( pObj );
988 if (pCustomShape)
990 double fExtraTextRotation = 0.0;
991 if ( mnFix16Angle && !( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 4 ) )
992 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
993 fExtraTextRotation = -mnFix16Angle;
995 if ( rObjData.nSpFlags & SP_FFLIPV ) // sj: in ppt the text is flipped, whereas in word the text
996 { // remains unchanged, so we have to take back the flipping here
997 fExtraTextRotation += 18000.0; // because our core will flip text if the shape is flipped.
999 fExtraTextRotation += nTextRotationAngle;
1000 if ( !::basegfx::fTools::equalZero( fExtraTextRotation ) )
1002 fExtraTextRotation /= 100.0;
1003 SdrCustomShapeGeometryItem aGeometryItem( static_cast<const SdrCustomShapeGeometryItem&>(pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )) );
1004 const OUString sTextRotateAngle( "TextRotateAngle" );
1005 css::beans::PropertyValue aPropVal;
1006 aPropVal.Name = sTextRotateAngle;
1007 aPropVal.Value <<= fExtraTextRotation;
1008 aGeometryItem.SetPropertyValue( aPropVal );
1009 pCustomShape->SetMergedItem( aGeometryItem );
1013 else if ( mnFix16Angle )
1015 // rotate text with shape ?
1016 double a = mnFix16Angle * nPi180;
1017 pObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
1018 sin( a ), cos( a ) );
1022 else if( !pObj )
1024 // simple rectangular objects are ignored by ImportObj() :-(
1025 // this is OK for Draw but not for Calc and Writer
1026 // cause here these objects have a default border
1027 pObj = new SdrRectObj(rTextRect);
1028 pObj->SetModel( pSdrModel );
1029 SfxItemSet aSet( pSdrModel->GetItemPool() );
1030 ApplyAttributes( rSt, aSet, rObjData );
1032 const SfxPoolItem* pPoolItem=nullptr;
1033 SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR,
1034 false, &pPoolItem );
1035 if( SfxItemState::DEFAULT == eState )
1036 aSet.Put( XFillColorItem( OUString(),
1037 Color( mnDefaultColor ) ) );
1038 pObj->SetMergedItemSet(aSet);
1041 // Means that fBehindDocument is set
1042 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
1043 pImpRec->bDrawHell = true;
1044 else
1045 pImpRec->bDrawHell = false;
1046 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
1047 pImpRec->bHidden = true;
1048 pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 );
1050 if ( nTextId )
1052 pImpRec->aTextId.nTxBxS = (sal_uInt16)( nTextId >> 16 );
1053 pImpRec->aTextId.nSequence = (sal_uInt16)nTextId;
1056 pImpRec->nDxWrapDistLeft = GetPropertyValue(
1057 DFF_Prop_dxWrapDistLeft, 114935L ) / 635L;
1058 pImpRec->nDyWrapDistTop = GetPropertyValue(
1059 DFF_Prop_dyWrapDistTop, 0 ) / 635L;
1060 pImpRec->nDxWrapDistRight = GetPropertyValue(
1061 DFF_Prop_dxWrapDistRight, 114935L ) / 635L;
1062 pImpRec->nDyWrapDistBottom = GetPropertyValue(
1063 DFF_Prop_dyWrapDistBottom, 0 ) / 635L;
1064 // 16.16 fraction times total image width or height, as appropriate.
1066 if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
1068 delete pImpRec->pWrapPolygon;
1069 pImpRec->pWrapPolygon = nullptr;
1071 sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1072 rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
1073 bool bOk = false;
1074 if (nNumElemVert && ((nElemSizeVert == 8) || (nElemSizeVert == 4)))
1076 //check if there is enough data in the file to make the
1077 //record sane
1078 bOk = rSt.remainingSize() / nElemSizeVert >= nNumElemVert;
1080 if (bOk)
1082 pImpRec->pWrapPolygon = new tools::Polygon(nNumElemVert);
1083 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
1085 sal_Int32 nX(0), nY(0);
1086 if (nElemSizeVert == 8)
1087 rSt.ReadInt32( nX ).ReadInt32( nY );
1088 else
1090 sal_Int16 nSmallX(0), nSmallY(0);
1091 rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
1092 nX = nSmallX;
1093 nY = nSmallY;
1095 (*(pImpRec->pWrapPolygon))[i].X() = nX;
1096 (*(pImpRec->pWrapPolygon))[i].Y() = nY;
1101 pImpRec->nCropFromTop = GetPropertyValue(
1102 DFF_Prop_cropFromTop, 0 );
1103 pImpRec->nCropFromBottom = GetPropertyValue(
1104 DFF_Prop_cropFromBottom, 0 );
1105 pImpRec->nCropFromLeft = GetPropertyValue(
1106 DFF_Prop_cropFromLeft, 0 );
1107 pImpRec->nCropFromRight = GetPropertyValue(
1108 DFF_Prop_cropFromRight, 0 );
1110 sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
1112 if ( !IsHardAttribute( DFF_Prop_fLine ) &&
1113 pImpRec->eShapeType == mso_sptPictureFrame )
1115 nLineFlags &= ~0x08;
1118 pImpRec->eLineStyle = (nLineFlags & 8)
1119 ? (MSO_LineStyle)GetPropertyValue(
1120 DFF_Prop_lineStyle,
1121 mso_lineSimple )
1122 : (MSO_LineStyle)USHRT_MAX;
1123 pImpRec->eLineDashing = (MSO_LineDashing)GetPropertyValue(
1124 DFF_Prop_lineDashing, mso_lineSolid );
1126 pImpRec->nFlags = rObjData.nSpFlags;
1128 if( pImpRec->nShapeId )
1130 // Complement Import Record List
1131 pImpRec->pObj = pObj;
1132 rImportData.m_Records.insert(std::unique_ptr<SvxMSDffImportRec>(pImpRec));
1134 // Complement entry in Z Order List with a pointer to this Object
1135 // Only store objects which are not deep inside the tree
1136 if( ( rObjData.nCalledByGroup == 0 )
1138 ( (rObjData.nSpFlags & SP_FGROUP)
1139 && (rObjData.nCalledByGroup < 2) )
1141 StoreShapeOrder( pImpRec->nShapeId,
1142 ( ( (sal_uLong)pImpRec->aTextId.nTxBxS ) << 16 )
1143 + pImpRec->aTextId.nSequence, pObj );
1145 else
1146 delete pImpRec;
1149 sal_uInt32 nBufferSize = GetPropertyValue( DFF_Prop_pihlShape, 0 );
1150 if( (0 < nBufferSize) && (nBufferSize <= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape, rSt ) )
1152 SvMemoryStream aMemStream;
1153 struct HyperLinksTable hlStr;
1154 sal_uInt16 nRawRecId,nRawRecSize;
1155 aMemStream.WriteUInt16( 0 ).WriteUInt16( nBufferSize );
1157 // copy from DFF stream to memory stream
1158 std::vector< sal_uInt8 > aBuffer( nBufferSize );
1159 sal_uInt8* pnData = &aBuffer.front();
1160 sal_uInt8 nStreamSize;
1161 if (pnData && rSt.ReadBytes(pnData, nBufferSize) == nBufferSize)
1163 aMemStream.WriteBytes(pnData, nBufferSize);
1164 aMemStream.Seek( STREAM_SEEK_TO_END );
1165 nStreamSize = aMemStream.Tell();
1166 aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
1167 bool bRet = 4 <= nStreamSize;
1168 if( bRet )
1169 aMemStream.ReadUInt16( nRawRecId ).ReadUInt16( nRawRecSize );
1170 SwDocShell* pDocShell = rReader.m_pDocShell;
1171 if(pDocShell)
1173 SwWW8ImplReader::ReadEmbeddedData( aMemStream, pDocShell, hlStr);
1177 if (pObj && !hlStr.hLinkAddr.isEmpty())
1179 SwMacroInfo* pInfo = GetMacroInfo( pObj, true );
1180 if( pInfo )
1182 pInfo->SetShapeId( rObjData.nShapeId );
1183 pInfo->SetHlink( hlStr.hLinkAddr );
1184 if (!hlStr.tarFrame.isEmpty())
1185 pInfo->SetTarFrame( hlStr.tarFrame );
1186 OUString aNameStr = GetPropertyString( DFF_Prop_wzName, rSt );
1187 if (!aNameStr.isEmpty())
1188 pInfo->SetName( aNameStr );
1193 return pObj;
1197 * Special FastSave - Attributes
1199 void SwWW8ImplReader::Read_StyleCode( sal_uInt16, const sal_uInt8* pData, short nLen )
1201 if (nLen < 0)
1203 m_bCpxStyle = false;
1204 return;
1206 sal_uInt16 nColl = 0;
1207 if (m_pWwFib->GetFIBVersion() <= ww::eWW2)
1208 nColl = *pData;
1209 else
1210 nColl = SVBT16ToShort(pData);
1211 if (nColl < m_vColl.size())
1213 SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[nColl] );
1214 m_bCpxStyle = true;
1219 * Read_Majority is for Majority (103) and Majority50 (108)
1221 void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short )
1226 * Stack
1228 void SwWW8FltControlStack::NewAttr(const SwPosition& rPos,
1229 const SfxPoolItem& rAttr)
1231 OSL_ENSURE(RES_TXTATR_FIELD != rAttr.Which(), "probably don't want to put"
1232 "fields into the control stack");
1233 OSL_ENSURE(RES_TXTATR_INPUTFIELD != rAttr.Which(), "probably don't want to put"
1234 "input fields into the control stack");
1235 OSL_ENSURE(RES_TXTATR_ANNOTATION != rAttr.Which(), "probably don't want to put"
1236 "annotations into the control stack");
1237 OSL_ENSURE(RES_FLTR_REDLINE != rAttr.Which(), "probably don't want to put"
1238 "redlines into the control stack");
1239 SwFltControlStack::NewAttr(rPos, rAttr);
1242 SwFltStackEntry* SwWW8FltControlStack::SetAttr(const SwPosition& rPos, sal_uInt16 nAttrId,
1243 bool bTstEnde, long nHand, bool )
1245 SwFltStackEntry *pRet = nullptr;
1246 // Doing a textbox, and using the control stack only as a temporary
1247 // collection point for properties which will are not to be set into
1248 // the real document
1249 if (rReader.m_pPlcxMan && rReader.m_pPlcxMan->GetDoingDrawTextBox())
1251 size_t nCnt = size();
1252 for (size_t i=0; i < nCnt; ++i)
1254 SwFltStackEntry& rEntry = (*this)[i];
1255 if (nAttrId == rEntry.pAttr->Which())
1257 DeleteAndDestroy(i--);
1258 --nCnt;
1262 else // Normal case, set the attribute into the document
1263 pRet = SwFltControlStack::SetAttr(rPos, nAttrId, bTstEnde, nHand);
1264 return pRet;
1267 long GetListFirstLineIndent(const SwNumFormat &rFormat)
1269 OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
1270 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1272 SvxAdjust eAdj = rFormat.GetNumAdjust();
1273 long nReverseListIndented;
1274 if (eAdj == SVX_ADJUST_RIGHT)
1275 nReverseListIndented = -rFormat.GetCharTextDistance();
1276 else if (eAdj == SVX_ADJUST_CENTER)
1277 nReverseListIndented = rFormat.GetFirstLineOffset()/2;
1278 else
1279 nReverseListIndented = rFormat.GetFirstLineOffset();
1280 return nReverseListIndented;
1283 static long lcl_GetTrueMargin(const SvxLRSpaceItem &rLR, const SwNumFormat &rFormat,
1284 long &rFirstLinePos)
1286 OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
1287 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1289 const long nBodyIndent = rLR.GetTextLeft();
1290 const long nFirstLineDiff = rLR.GetTextFirstLineOfst();
1291 rFirstLinePos = nBodyIndent + nFirstLineDiff;
1293 const long nPseudoListBodyIndent = rFormat.GetAbsLSpace();
1294 const long nReverseListIndented = GetListFirstLineIndent(rFormat);
1295 long nExtraListIndent = nPseudoListBodyIndent + nReverseListIndented;
1297 return nExtraListIndent > 0 ? nExtraListIndent : 0;
1300 // #i103711#
1301 // #i105414#
1302 void SyncIndentWithList( SvxLRSpaceItem &rLR,
1303 const SwNumFormat &rFormat,
1304 const bool bFirstLineOfstSet,
1305 const bool bLeftIndentSet )
1307 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1309 long nWantedFirstLinePos;
1310 long nExtraListIndent = lcl_GetTrueMargin(rLR, rFormat, nWantedFirstLinePos);
1311 rLR.SetTextLeft(nWantedFirstLinePos - nExtraListIndent);
1312 rLR.SetTextFirstLineOfst(0);
1314 else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1316 if ( !bFirstLineOfstSet && bLeftIndentSet &&
1317 rFormat.GetFirstLineIndent() != 0 )
1319 rLR.SetTextFirstLineOfst( rFormat.GetFirstLineIndent() );
1321 else if ( bFirstLineOfstSet && !bLeftIndentSet &&
1322 rFormat.GetIndentAt() != 0 )
1324 rLR.SetTextLeft( rFormat.GetIndentAt() );
1326 else if (!bFirstLineOfstSet && !bLeftIndentSet )
1328 if ( rFormat.GetFirstLineIndent() != 0 )
1330 rLR.SetTextFirstLineOfst( rFormat.GetFirstLineIndent() );
1332 if ( rFormat.GetIndentAt() != 0 )
1334 rLR.SetTextLeft( rFormat.GetIndentAt() );
1340 const SwNumFormat* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition &rPos,
1341 const SwTextNode &rTextNode)
1343 const SwNumFormat *pRet = nullptr;
1344 const SfxPoolItem *pItem = GetStackAttr(rPos, RES_FLTR_NUMRULE);
1345 if (pItem && rTextNode.GetNumRule())
1347 if (rTextNode.IsCountedInList())
1349 OUString sName(static_cast<const SfxStringItem*>(pItem)->GetValue());
1350 const SwNumRule *pRule = pDoc->FindNumRulePtr(sName);
1351 if (pRule)
1352 pRet = GetNumFormatFromSwNumRuleLevel(*pRule, rTextNode.GetActualListLevel());
1355 return pRet;
1358 sal_Int32 SwWW8FltControlStack::GetCurrAttrCP() const
1360 return rReader.GetCurrAttrCP();
1363 bool SwWW8FltControlStack::IsParaEndInCPs(sal_Int32 nStart,sal_Int32 nEnd,bool bSdOD) const
1365 return rReader.IsParaEndInCPs(nStart,nEnd,bSdOD);
1369 * Clear the para end position recorded in reader intermittently
1370 * for the least impact on loading performance.
1372 void SwWW8FltControlStack::ClearParaEndPosition()
1374 if ( !empty() )
1375 return;
1377 rReader.ClearParaEndPosition();
1380 bool SwWW8FltControlStack::CheckSdOD(sal_Int32 nStart,sal_Int32 nEnd)
1382 return rReader.IsParaEndInCPs(nStart,nEnd);
1385 void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition& rTmpPos,
1386 SwFltStackEntry& rEntry )
1388 switch( rEntry.pAttr->Which() )
1390 case RES_FLTR_BOOKMARK:
1392 // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1393 // and which is not referenced.
1394 bool bInsertBookmarkIntoDoc = true;
1396 SwFltBookmark* pFltBookmark = dynamic_cast<SwFltBookmark*>(rEntry.pAttr);
1397 if ( pFltBookmark != nullptr && pFltBookmark->IsTOCBookmark() )
1399 const OUString& rName = pFltBookmark->GetName();
1400 std::set< OUString, SwWW8::ltstr >::const_iterator aResult = aReferencedTOCBookmarks.find(rName);
1401 if ( aResult == aReferencedTOCBookmarks.end() )
1403 bInsertBookmarkIntoDoc = false;
1406 if ( bInsertBookmarkIntoDoc )
1408 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1410 break;
1412 default:
1413 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1414 break;
1419 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos,
1420 SwFltStackEntry& rEntry)
1422 switch (rEntry.pAttr->Which())
1424 case RES_LR_SPACE:
1427 Loop over the affected nodes and
1428 a) convert the word style absolute indent to indent relative
1429 to any numbering indent active on the nodes
1430 b) adjust the writer style tabstops relative to the old
1431 paragraph indent to be relative to the new paragraph indent
1433 using namespace sw::util;
1434 SwPaM aRegion(rTmpPos);
1435 if (rEntry.MakeRegion(pDoc, aRegion, false))
1437 SvxLRSpaceItem aNewLR( *static_cast<SvxLRSpaceItem*>(rEntry.pAttr) );
1438 sal_uLong nStart = aRegion.Start()->nNode.GetIndex();
1439 sal_uLong nEnd = aRegion.End()->nNode.GetIndex();
1440 for(; nStart <= nEnd; ++nStart)
1442 SwNode* pNode = pDoc->GetNodes()[ nStart ];
1443 if (!pNode || !pNode->IsTextNode())
1444 continue;
1446 SwContentNode* pNd = static_cast<SwContentNode*>(pNode);
1447 SvxLRSpaceItem aOldLR = static_cast<const SvxLRSpaceItem&>(pNd->GetAttr(RES_LR_SPACE));
1449 SwTextNode *pTextNode = static_cast<SwTextNode*>(pNode);
1451 const SwNumFormat *pNum = nullptr;
1452 pNum = GetNumFormatFromStack( *aRegion.GetPoint(), *pTextNode );
1453 if (!pNum)
1455 pNum = GetNumFormatFromTextNode(*pTextNode);
1458 if ( pNum )
1460 // #i103711#
1461 const bool bFirstLineIndentSet =
1462 ( rReader.m_aTextNodesHavingFirstLineOfstSet.end() !=
1463 rReader.m_aTextNodesHavingFirstLineOfstSet.find( pNode ) );
1464 // #i105414#
1465 const bool bLeftIndentSet =
1466 ( rReader.m_aTextNodesHavingLeftIndentSet.end() !=
1467 rReader.m_aTextNodesHavingLeftIndentSet.find( pNode ) );
1468 SyncIndentWithList( aNewLR, *pNum,
1469 bFirstLineIndentSet,
1470 bLeftIndentSet );
1473 if (aNewLR == aOldLR)
1474 continue;
1476 pNd->SetAttr(aNewLR);
1481 break;
1483 case RES_TXTATR_FIELD:
1484 OSL_ENSURE(false, "What is a field doing in the control stack,"
1485 "probably should have been in the endstack");
1486 break;
1488 case RES_TXTATR_ANNOTATION:
1489 OSL_ENSURE(false, "What is a annotation doing in the control stack,"
1490 "probably should have been in the endstack");
1491 break;
1493 case RES_TXTATR_INPUTFIELD:
1494 OSL_ENSURE(false, "What is a input field doing in the control stack,"
1495 "probably should have been in the endstack");
1496 break;
1498 case RES_TXTATR_INETFMT:
1500 SwPaM aRegion(rTmpPos);
1501 if (rEntry.MakeRegion(pDoc, aRegion, false))
1503 SwFrameFormat *pFrame;
1504 // If we have just one single inline graphic then
1505 // don't insert a field for the single frame, set
1506 // the frames hyperlink field attribute directly.
1507 if (nullptr != (pFrame = SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion)))
1509 const SwFormatINetFormat *pAttr = static_cast<const SwFormatINetFormat *>(
1510 rEntry.pAttr);
1511 SwFormatURL aURL;
1512 aURL.SetURL(pAttr->GetValue(), false);
1513 aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1514 pFrame->SetFormatAttr(aURL);
1516 else
1518 pDoc->getIDocumentContentOperations().InsertPoolItem(aRegion, *rEntry.pAttr);
1522 break;
1523 default:
1524 SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1525 break;
1529 const SfxPoolItem* SwWW8FltControlStack::GetFormatAttr(const SwPosition& rPos,
1530 sal_uInt16 nWhich)
1532 const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1533 if (!pItem)
1535 SwContentNode const*const pNd = rPos.nNode.GetNode().GetContentNode();
1536 if (!pNd)
1537 pItem = &pDoc->GetAttrPool().GetDefaultItem(nWhich);
1538 else
1541 If we're hunting for the indent on a paragraph and need to use the
1542 parent style indent, then return the indent in msword format, and
1543 not writer format, because that's the style that the filter works
1544 in (naturally)
1546 if (nWhich == RES_LR_SPACE)
1548 SfxItemState eState = SfxItemState::DEFAULT;
1549 if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1550 eState = pSet->GetItemState(RES_LR_SPACE, false);
1551 if (eState != SfxItemState::SET && rReader.m_nAktColl < rReader.m_vColl.size())
1552 pItem = &(rReader.m_vColl[rReader.m_nAktColl].maWordLR);
1556 If we're hunting for a character property, try and exact position
1557 within the text node for lookup
1559 if (pNd->IsTextNode())
1561 const sal_Int32 nPos = rPos.nContent.GetIndex();
1562 m_xScratchSet.reset(new SfxItemSet(pDoc->GetAttrPool(), nWhich, nWhich));
1563 if (pNd->GetTextNode()->GetAttr(*m_xScratchSet, nPos, nPos))
1564 pItem = m_xScratchSet->GetItem(nWhich);
1567 if (!pItem)
1568 pItem = &pNd->GetAttr(nWhich);
1571 return pItem;
1574 const SfxPoolItem* SwWW8FltControlStack::GetStackAttr(const SwPosition& rPos,
1575 sal_uInt16 nWhich)
1577 SwFltPosition aFltPos(rPos);
1579 size_t nSize = size();
1580 while (nSize)
1582 const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1583 if (rEntry.pAttr->Which() == nWhich)
1585 if ( (rEntry.bOpen) ||
1587 (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1588 (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1589 (rEntry.m_aMkPos.m_nContent <= aFltPos.m_nContent) &&
1590 (rEntry.m_aPtPos.m_nContent > aFltPos.m_nContent)
1594 * e.g. half-open range [0-3) so asking for properties at 3
1595 * means props that end at 3 are not included
1598 return rEntry.pAttr;
1602 return nullptr;
1605 bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1606 const SwFormatField& rFormatField,
1607 sal_uInt16& rBkmNo)
1609 const SwField* pField = rFormatField.GetField();
1610 sal_uInt16 nSubType;
1611 if(pField && (RES_GETREFFLD == pField->Which())
1612 && ((REF_FOOTNOTE == (nSubType = pField->GetSubType())) || (REF_ENDNOTE == nSubType))
1613 && !static_cast<const SwGetRefField*>(pField)->GetSetRefName().isEmpty())
1615 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1616 IDocumentMarkAccess::const_iterator_t ppBkmk =
1617 pMarkAccess->findMark( static_cast<const SwGetRefField*>(pField)->GetSetRefName() );
1618 if(ppBkmk != pMarkAccess->getAllMarksEnd())
1620 // find Sequence No of corresponding Foot-/Endnote
1621 rBkmNo = ppBkmk - pMarkAccess->getAllMarksBegin();
1622 return true;
1625 return false;
1628 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition& rTmpPos,
1629 SwFltStackEntry& rEntry)
1631 switch (rEntry.pAttr->Which())
1634 Look up these in our lists of bookmarks that were changed to
1635 variables, and replace the ref field with a var field, otherwise
1636 do normal (?) strange stuff
1638 case RES_TXTATR_FIELD:
1639 case RES_TXTATR_ANNOTATION:
1640 case RES_TXTATR_INPUTFIELD:
1642 SwNodeIndex aIdx(rEntry.m_aMkPos.m_nNode, 1);
1643 SwPaM aPaM(aIdx, rEntry.m_aMkPos.m_nContent);
1645 SwFormatField& rFormatField = *static_cast<SwFormatField*>(rEntry.pAttr);
1646 SwField* pField = rFormatField.GetField();
1648 if (!RefToVar(pField, rEntry))
1650 sal_uInt16 nBkmNo;
1651 if( IsFootnoteEdnBkmField(rFormatField, nBkmNo) )
1653 ::sw::mark::IMark const * const pMark = (pDoc->getIDocumentMarkAccess()->getAllMarksBegin() + nBkmNo)->get();
1655 const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1657 SwTextNode* pText = rBkMrkPos.nNode.GetNode().GetTextNode();
1658 if( pText && rBkMrkPos.nContent.GetIndex() )
1660 SwTextAttr* const pFootnote = pText->GetTextAttrForCharAt(
1661 rBkMrkPos.nContent.GetIndex()-1, RES_TXTATR_FTN );
1662 if( pFootnote )
1664 sal_uInt16 nRefNo = static_cast<SwTextFootnote*>(pFootnote)->GetSeqRefNo();
1666 static_cast<SwGetRefField*>(pField)->SetSeqNo( nRefNo );
1668 if( pFootnote->GetFootnote().IsEndNote() )
1669 static_cast<SwGetRefField*>(pField)->SetSubType(REF_ENDNOTE);
1675 pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, *rEntry.pAttr);
1676 MoveAttrs(*aPaM.GetPoint());
1678 break;
1679 case RES_FLTR_TOX:
1680 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1681 break;
1682 default:
1683 case RES_FLTR_BOOKMARK:
1684 OSL_ENSURE(false, "EndStck used with non field, not what we want");
1685 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1686 break;
1691 For styles we will do our tabstop arithmetic in word style and adjust them to
1692 writer style after all the styles have been finished and the dust settles as
1693 to what affects what.
1695 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1696 word indexes and we'll turn them back into writer indexes when setting them
1697 into the document. If explicit left indent exist which affects them, then this
1698 is handled when the explicit left indent is set into the document
1700 void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1702 if (nLen < 0)
1704 m_pCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_TABSTOP);
1705 return;
1708 sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1709 const sal_uInt8* pDel = pData + 1; // Del - Array
1711 sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1712 const sal_uInt8* pIns = pData + 2*nDel + 2; // Ins - Array
1714 short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1715 if (nRequiredLength > nLen)
1717 // would require more data than available to describe!
1718 // discard invalid record
1719 nIns = 0;
1720 nDel = 0;
1723 WW8_TBD const * pTyp = reinterpret_cast<WW8_TBD const *>(pData + 2*nDel + 2*nIns + 2); // Type Array
1725 SvxTabStopItem aAttr(0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP);
1727 const SwTextFormatColl* pSty = nullptr;
1728 sal_uInt16 nTabBase;
1729 if (m_pAktColl && m_nAktColl < m_vColl.size()) // StyleDef
1731 nTabBase = m_vColl[m_nAktColl].m_nBase;
1732 if (nTabBase < m_vColl.size()) // Based On
1733 pSty = static_cast<const SwTextFormatColl*>(m_vColl[nTabBase].m_pFormat);
1735 else
1736 { // Text
1737 nTabBase = m_nAktColl;
1738 if (m_nAktColl < m_vColl.size())
1739 pSty = static_cast<const SwTextFormatColl*>(m_vColl[m_nAktColl].m_pFormat);
1740 //TODO: figure out else here
1743 bool bFound = false;
1744 std::unordered_set<size_t> aLoopWatch;
1745 while (pSty && !bFound)
1747 const SfxPoolItem* pTabs;
1748 bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1749 &pTabs) == SfxItemState::SET;
1750 if( bFound )
1751 aAttr = *static_cast<const SvxTabStopItem*>(pTabs);
1752 else
1754 sal_uInt16 nOldTabBase = nTabBase;
1755 // If based on another
1756 if (nTabBase < m_vColl.size())
1757 nTabBase = m_vColl[nTabBase].m_nBase;
1759 if (
1760 nTabBase < m_vColl.size() &&
1761 nOldTabBase != nTabBase &&
1762 nTabBase != ww::stiNil
1765 // #i61789: Stop searching when next style is the same as the
1766 // current one (prevent loop)
1767 aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1768 if (nTabBase < m_vColl.size())
1769 pSty = static_cast<const SwTextFormatColl*>(m_vColl[nTabBase].m_pFormat);
1770 //TODO figure out the else branch
1772 if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1773 aLoopWatch.end())
1774 pSty = nullptr;
1776 else
1777 pSty = nullptr; // Give up on the search
1781 SvxTabStop aTabStop;
1782 for (short i=0; i < nDel; ++i)
1784 sal_uInt16 nPos = aAttr.GetPos(SVBT16ToShort(pDel + i*2));
1785 if( nPos != SVX_TAB_NOTFOUND )
1786 aAttr.Remove( nPos );
1789 for (short i=0; i < nIns; ++i)
1791 short nPos = SVBT16ToShort(pIns + i*2);
1792 aTabStop.GetTabPos() = nPos;
1793 switch( pTyp[i].aBits1 & 0x7 ) // pTyp[i].jc
1795 case 0:
1796 aTabStop.GetAdjustment() = SvxTabAdjust::Left;
1797 break;
1798 case 1:
1799 aTabStop.GetAdjustment() = SvxTabAdjust::Center;
1800 break;
1801 case 2:
1802 aTabStop.GetAdjustment() = SvxTabAdjust::Right;
1803 break;
1804 case 3:
1805 aTabStop.GetAdjustment() = SvxTabAdjust::Decimal;
1806 break;
1807 case 4:
1808 continue; // Ignore Bar
1811 switch( pTyp[i].aBits1 >> 3 & 0x7 )
1813 case 0:
1814 aTabStop.GetFill() = ' ';
1815 break;
1816 case 1:
1817 aTabStop.GetFill() = '.';
1818 break;
1819 case 2:
1820 aTabStop.GetFill() = '-';
1821 break;
1822 case 3:
1823 case 4:
1824 aTabStop.GetFill() = '_';
1825 break;
1828 sal_uInt16 nPos2 = aAttr.GetPos( nPos );
1829 if (nPos2 != SVX_TAB_NOTFOUND)
1830 aAttr.Remove(nPos2); // Or else Insert() refuses
1831 aAttr.Insert(aTabStop);
1834 if (nIns || nDel)
1835 NewAttr(aAttr);
1836 else
1838 // Here we have a tab definition which inserts no extra tabs, or deletes
1839 // no existing tabs. An older version of writer is probably the creater
1840 // of the document :-( . So if we are importing a style we can just
1841 // ignore it. But if we are importing into text we cannot as during
1842 // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1843 // the range the attrib affects, and ignoring it would upset the
1844 // balance
1845 if (!m_pAktColl) // not importing into a style
1847 using namespace sw::util;
1848 SvxTabStopItem aOrig = pSty ?
1849 ItemGet<SvxTabStopItem>(*pSty, RES_PARATR_TABSTOP) :
1850 DefaultItemGet<SvxTabStopItem>(m_rDoc, RES_PARATR_TABSTOP);
1851 NewAttr(aOrig);
1857 * DOP
1859 void SwWW8ImplReader::ImportDop()
1861 // correct the LastPrinted date in DocumentProperties
1862 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1863 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1864 uno::Reference<document::XDocumentProperties> xDocuProps(
1865 xDPS->getDocumentProperties());
1866 OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null");
1867 if (xDocuProps.is())
1869 DateTime aLastPrinted(
1870 msfilter::util::DTTM2DateTime(m_pWDop->dttmLastPrint));
1871 ::util::DateTime uDT = aLastPrinted.GetUNODateTime();
1872 xDocuProps->setPrintDate(uDT);
1875 // COMPATIBILITY FLAGS START
1877 // #i78951# - remember the unknown compatibility options
1878 // so as to export them out
1879 m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1( m_pWDop->GetCompatibilityOptions());
1880 m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2( m_pWDop->GetCompatibilityOptions2());
1882 // The distance between two paragraphs is the sum of the bottom distance of
1883 // the first paragraph and the top distance of the second one
1884 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX, m_pWDop->fDontUseHTMLAutoSpacing);
1885 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, true );
1886 // move tabs on alignment
1887 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT, true);
1888 // #i24363# tab stops relative to indent
1889 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT, false);
1891 // Import Default Tabs
1892 long nDefTabSiz = m_pWDop->dxaTab;
1893 if( nDefTabSiz < 56 )
1894 nDefTabSiz = 709;
1896 // We want exactly one DefaultTab
1897 SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SvxTabAdjust::Default, RES_PARATR_TABSTOP );
1898 const_cast<SvxTabStop&>(aNewTab[0]).GetAdjustment() = SvxTabAdjust::Default;
1900 m_rDoc.GetAttrPool().SetPoolDefaultItem( aNewTab );
1902 // Import zoom factor
1903 if (m_pWDop->wScaleSaved)
1905 uno::Sequence<beans::PropertyValue> aViewProps(3);
1906 aViewProps[0].Name = "ZoomFactor";
1907 aViewProps[0].Value <<= sal_Int16(m_pWDop->wScaleSaved);
1908 aViewProps[1].Name = "VisibleBottom";
1909 aViewProps[1].Value <<= sal_Int32(0);
1910 aViewProps[2].Name = "ZoomType";
1911 //Import zoom type
1912 switch (m_pWDop->zkSaved) {
1913 case 1: aViewProps[2].Value <<= sal_Int16(SvxZoomType::WHOLEPAGE); break;
1914 case 2: aViewProps[2].Value <<= sal_Int16(SvxZoomType::PAGEWIDTH); break;
1915 case 3: aViewProps[2].Value <<= sal_Int16(SvxZoomType::OPTIMAL); break;
1916 default: aViewProps[2].Value <<= sal_Int16(SvxZoomType::PERCENT); break;
1919 uno::Reference< uno::XComponentContext > xComponentContext(comphelper::getProcessComponentContext());
1920 uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(xComponentContext);
1921 xBox->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps));
1922 uno::Reference<container::XIndexAccess> xIndexAccess(xBox, uno::UNO_QUERY);
1923 uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
1924 xViewDataSupplier->setViewData(xIndexAccess);
1927 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE, !m_pWDop->fUsePrinterMetrics);
1928 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE, true);
1929 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS, true );
1930 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, !m_pWDop->fNoLeading);
1931 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING, false);
1932 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING, false); // #i47448#
1933 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, !m_pWDop->fExpShRtn); // #i49277#, #i56856#
1934 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT, false); // #i53199#
1935 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING, false);
1937 // #i25901# - set new compatibility option
1938 // 'Add paragraph and table spacing at bottom of table cells'
1939 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, true);
1941 // #i11860# - set new compatibility option
1942 // 'Use former object positioning' to <false>
1943 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS, false);
1945 // #i27767# - set new compatibility option
1946 // 'Consider Wrapping mode when positioning object' to <true>
1947 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, true);
1949 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, false); // #i13832#, #i24135#
1951 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1953 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, true); // #i3952#
1955 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING, true);
1956 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA, true);
1957 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVERFLOW, true);
1958 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS, true);
1959 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES, true);
1960 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
1961 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL, true);
1962 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE, true);
1963 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ALLOW_PADDING_WITHOUT_BORDERS, true);
1965 // COMPATIBILITY FLAGS END
1967 // Import magic doptypography information, if its there
1968 if (m_pWwFib->m_nFib > 105)
1969 ImportDopTypography(m_pWDop->doptypography);
1971 // disable form design mode to be able to use imported controls directly
1972 // #i31239# always disable form design mode, not only in protected docs
1974 using namespace com::sun::star;
1976 uno::Reference<lang::XComponent> xModelComp(m_pDocShell->GetModel(),
1977 uno::UNO_QUERY);
1978 uno::Reference<beans::XPropertySet> xDocProps(xModelComp,
1979 uno::UNO_QUERY);
1980 if (xDocProps.is())
1982 uno::Reference<beans::XPropertySetInfo> xInfo =
1983 xDocProps->getPropertySetInfo();
1984 if (xInfo.is())
1986 if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1988 bool bValue = false;
1989 xDocProps->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(bValue));
1995 // Still allow editing of form fields.
1996 if (!m_pWDop->fProtEnabled)
1997 m_pDocShell->SetModifyPasswordHash(m_pWDop->lKeyProtDoc);
1999 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
2000 if (rOpt.IsUseEnhancedFields())
2001 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM, m_pWDop->fProtEnabled );
2004 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography &rTypo)
2006 using namespace com::sun::star;
2007 switch (rTypo.iLevelOfKinsoku)
2009 case 2: // custom
2011 i18n::ForbiddenCharacters aForbidden(rTypo.rgxchFPunct,
2012 rTypo.rgxchLPunct);
2013 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(rTypo.GetConvertedLang(),
2014 aForbidden);
2015 // Obviously cannot set the standard level 1 for japanese, so
2016 // bail out now while we can.
2017 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
2018 return;
2020 break;
2021 default:
2022 break;
2026 This MS hack means that level 2 of japanese is not in operation, so we put
2027 in what we know are the MS defaults, there is a complementary reverse
2028 hack in the writer. Its our default as well, but we can set it anyway
2029 as a flag for later.
2031 if (!rTypo.reserved2)
2033 i18n::ForbiddenCharacters aForbidden(WW8DopTypography::GetJapanNotBeginLevel1(),
2034 WW8DopTypography::GetJapanNotEndLevel1());
2035 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESE,aForbidden);
2038 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION, rTypo.fKerningPunct);
2039 m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<SwCharCompressType>(rTypo.iJustification));
2043 * Footnotes and Endnotes
2045 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader* pRdr ,WW8_CP nStartCp) :
2046 maTmpPos(*pRdr->m_pPaM->GetPoint()),
2047 mpOldStck(pRdr->m_pCtrlStck),
2048 mpOldAnchorStck(pRdr->m_pAnchorStck),
2049 mpOldRedlines(pRdr->m_pRedlineStack),
2050 mpOldPlcxMan(pRdr->m_pPlcxMan),
2051 mpWFlyPara(pRdr->m_pWFlyPara),
2052 mpSFlyPara(pRdr->m_pSFlyPara),
2053 mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
2054 mpPrevNumRule(pRdr->m_pPrevNumRule),
2055 mpTableDesc(pRdr->m_pTableDesc),
2056 mnInTable(pRdr->m_nInTable),
2057 mnAktColl(pRdr->m_nAktColl),
2058 mcSymbol(pRdr->m_cSymbol),
2059 mbIgnoreText(pRdr->m_bIgnoreText),
2060 mbSymbol(pRdr->m_bSymbol),
2061 mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2062 mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2063 mbAnl(pRdr->m_bAnl),
2064 mbInHyperlink(pRdr->m_bInHyperlink),
2065 mbPgSecBreak(pRdr->m_bPgSecBreak),
2066 mbWasParaEnd(pRdr->m_bWasParaEnd),
2067 mbHasBorder(pRdr->m_bHasBorder),
2068 mbFirstPara(pRdr->m_bFirstPara)
2070 pRdr->m_bSymbol = false;
2071 pRdr->m_bHdFtFootnoteEdn = true;
2072 pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2073 = pRdr->m_bHasBorder = false;
2074 pRdr->m_bFirstPara = true;
2075 pRdr->m_nInTable = 0;
2076 pRdr->m_pWFlyPara = nullptr;
2077 pRdr->m_pSFlyPara = nullptr;
2078 pRdr->m_pPreviousNumPaM = nullptr;
2079 pRdr->m_pPrevNumRule = nullptr;
2080 pRdr->m_pTableDesc = nullptr;
2081 pRdr->m_nAktColl = 0;
2083 pRdr->m_pCtrlStck = new SwWW8FltControlStack(&pRdr->m_rDoc, pRdr->m_nFieldFlags,
2084 *pRdr);
2086 pRdr->m_pRedlineStack = new sw::util::RedlineStack(pRdr->m_rDoc);
2088 pRdr->m_pAnchorStck = new SwWW8FltAnchorStack(&pRdr->m_rDoc, pRdr->m_nFieldFlags);
2090 // Save the attribute manager: we need this as the newly created PLCFx Manager
2091 // access the same FKPs as the old one and their Start-End position changes.
2092 if (pRdr->m_pPlcxMan)
2093 pRdr->m_pPlcxMan->SaveAllPLCFx(maPLCFxSave);
2095 if (nStartCp != -1)
2097 pRdr->m_pPlcxMan = new WW8PLCFMan(pRdr->m_pSBase,
2098 mpOldPlcxMan->GetManType(), nStartCp);
2101 maOldApos.push_back(false);
2102 maOldApos.swap(pRdr->m_aApos);
2103 maOldFieldStack.swap(pRdr->m_aFieldStack);
2106 void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
2108 pRdr->m_pWFlyPara = mpWFlyPara;
2109 pRdr->m_pSFlyPara = mpSFlyPara;
2110 pRdr->m_pPreviousNumPaM = mpPreviousNumPaM;
2111 pRdr->m_pPrevNumRule = mpPrevNumRule;
2112 pRdr->m_pTableDesc = mpTableDesc;
2113 pRdr->m_cSymbol = mcSymbol;
2114 pRdr->m_bSymbol = mbSymbol;
2115 pRdr->m_bIgnoreText = mbIgnoreText;
2116 pRdr->m_bHdFtFootnoteEdn = mbHdFtFootnoteEdn;
2117 pRdr->m_bTxbxFlySection = mbTxbxFlySection;
2118 pRdr->m_nInTable = mnInTable;
2119 pRdr->m_bAnl = mbAnl;
2120 pRdr->m_bInHyperlink = mbInHyperlink;
2121 pRdr->m_bWasParaEnd = mbWasParaEnd;
2122 pRdr->m_bPgSecBreak = mbPgSecBreak;
2123 pRdr->m_nAktColl = mnAktColl;
2124 pRdr->m_bHasBorder = mbHasBorder;
2125 pRdr->m_bFirstPara = mbFirstPara;
2127 // Close all attributes as attributes could be created that extend the Fly
2128 pRdr->DeleteCtrlStack();
2129 pRdr->m_pCtrlStck = mpOldStck;
2131 pRdr->m_pRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2132 delete pRdr->m_pRedlineStack;
2133 pRdr->m_pRedlineStack = mpOldRedlines;
2135 pRdr->DeleteAnchorStack();
2136 pRdr->m_pAnchorStck = mpOldAnchorStck;
2138 *pRdr->m_pPaM->GetPoint() = maTmpPos;
2140 if (mpOldPlcxMan != pRdr->m_pPlcxMan)
2142 delete pRdr->m_pPlcxMan;
2143 pRdr->m_pPlcxMan = mpOldPlcxMan;
2145 if (pRdr->m_pPlcxMan)
2146 pRdr->m_pPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2147 pRdr->m_aApos.swap(maOldApos);
2148 pRdr->m_aFieldStack.swap(maOldFieldStack);
2151 void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex* pSttIdx,
2152 WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2154 // Saves Flags (amongst other things) and resets them
2155 WW8ReaderSave aSave( this );
2157 m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2158 m_pPaM->GetPoint()->nContent.Assign( m_pPaM->GetContentNode(), 0 );
2160 // Read Text for Header, Footer or Footnote
2161 ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2162 aSave.Restore( this );
2166 * Use authornames, if not available fall back to initials.
2168 long SwWW8ImplReader::Read_And(WW8PLCFManResult* pRes)
2170 WW8PLCFx_SubDoc* pSD = m_pPlcxMan->GetAtn();
2171 if (!pSD)
2172 return 0;
2174 const void* pData = pSD->GetData();
2175 if (!pData)
2176 return 0;
2178 OUString sAuthor;
2179 OUString sInitials;
2180 if( m_bVer67 )
2182 const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2183 const OUString* pA = GetAnnotationAuthor(SVBT16ToShort(pDescri->ibst));
2184 if (pA)
2185 sAuthor = *pA;
2186 else
2188 const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2189 SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2190 sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252);
2193 else
2195 const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2197 const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToShort(pDescri->xstUsrInitl[0]),
2198 SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2199 OUStringBuffer aBuf;
2200 aBuf.setLength(nLen);
2201 for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2202 aBuf[nIdx-1] = SVBT16ToShort(pDescri->xstUsrInitl[nIdx]);
2203 sInitials = aBuf.makeStringAndClear();
2206 if (const OUString* pA = GetAnnotationAuthor(SVBT16ToShort(pDescri->ibst)))
2207 sAuthor = *pA;
2208 else
2209 sAuthor = sInitials;
2212 sal_uInt32 nDateTime = 0;
2214 if (sal_uInt8 * pExtended = m_pPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2216 sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2217 if (m_pWwFib->m_lcbAtrdExtra/18 > nIndex)
2218 nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2221 DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2223 OUString sText;
2224 OutlinerParaObject *pOutliner = ImportAsOutliner( sText, pRes->nCp2OrIdx,
2225 pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2227 m_pFormatOfJustInsertedApo = nullptr;
2228 SwPostItField aPostIt(
2229 static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(RES_POSTITFLD)), sAuthor,
2230 sText, sInitials, OUString(), aDate );
2231 aPostIt.SetTextObject(pOutliner);
2233 SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2234 m_pCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2235 m_rDoc.getIDocumentContentOperations().InsertPoolItem(aEnd, SwFormatField(aPostIt));
2236 m_pCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2237 // If this is a range, make sure that it ends after the just inserted character, not before it.
2238 m_pReffedStck->MoveAttrs(*aEnd.GetPoint());
2240 return 0;
2243 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart, WW8_CP nLen,
2244 SwFrameFormat &rHdFtFormat, sal_uInt16 nPageWidth)
2246 const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2247 OSL_ENSURE(pSttIdx, "impossible");
2248 if (!pSttIdx)
2249 return;
2251 SwPosition aTmpPos(*m_pPaM->GetPoint());
2253 m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2254 m_pPaM->GetPoint()->nContent.Assign(m_pPaM->GetContentNode(), 0);
2256 SwFlyFrameFormat *pFrame = m_rDoc.MakeFlySection(FLY_AT_PARA, m_pPaM->GetPoint());
2258 SwFormatAnchor aAnch( pFrame->GetAnchor() );
2259 aAnch.SetType( FLY_AT_PARA );
2260 pFrame->SetFormatAttr( aAnch );
2261 SwFormatFrameSize aSz(ATT_MIN_SIZE, nPageWidth, MINLAY);
2262 SwFrameSize eFrameSize = ATT_MIN_SIZE;
2263 if( eFrameSize != aSz.GetWidthSizeType() )
2264 aSz.SetWidthSizeType( eFrameSize );
2265 pFrame->SetFormatAttr(aSz);
2266 pFrame->SetFormatAttr(SwFormatSurround(SURROUND_THROUGHT));
2267 pFrame->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
2269 // #i43427# - send frame for header/footer into background.
2270 pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2271 SdrObject* pFrameObj = CreateContactObject( pFrame );
2272 OSL_ENSURE( pFrameObj,
2273 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2274 if ( pFrameObj )
2276 pFrameObj->SetOrdNum( 0L );
2278 MoveInsideFly(pFrame);
2280 const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2282 Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2284 MoveOutsideFly(pFrame, aTmpPos);
2287 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat* pHdFtFormat)
2289 const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2290 if (!pSttIdx)
2291 return;
2293 SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2295 Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2297 *m_pPaM->GetPoint() = aTmpPos;
2300 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP) const
2302 // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2303 return (nHeaderCP < m_pWwFib->m_ccpHdr && nHeaderCP >= 0);
2306 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems, sal_uInt8 grpfIhdt,
2307 int nSect)
2309 if (m_pHdFt)
2311 WW8_CP nStart, nLen;
2312 sal_uInt8 nNumber = 5;
2314 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2316 if (nI & nWhichItems)
2318 bool bOk = true;
2319 if( m_bVer67 )
2320 bOk = ( m_pHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2321 else
2323 m_pHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2324 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2327 if (bOk)
2328 return true;
2332 return false;
2335 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2336 const wwSection &rSection)
2338 sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2339 SwPageDesc *pPD = rSection.mpPage;
2341 if( m_pHdFt )
2343 WW8_CP nStart, nLen;
2344 sal_uInt8 nNumber = 5;
2346 // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2347 // corresponding to bit fields in grpfIhdt indicating which
2348 // header/footer(s) are present in this section
2349 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2351 if (nI & grpfIhdt)
2353 bool bOk = true;
2354 if( m_bVer67 )
2355 bOk = ( m_pHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2356 else
2358 m_pHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2359 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2362 bool bUseLeft
2363 = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2364 bool bUseFirst
2365 = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2367 // If we are loading a first-page header/footer which is not
2368 // actually enabled in this section (it still needs to be
2369 // loaded as it may be inherited by a later section)
2370 bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2372 bool bFooter
2373 = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2375 SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2376 : bUseFirst ? pPD->GetFirstMaster()
2377 : pPD->GetMaster();
2379 SwFrameFormat* pHdFtFormat;
2380 // If we have empty first page header and footer.
2381 bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2382 if (bFooter)
2384 m_bIsFooter = true;
2385 //#i17196# Cannot have left without right
2386 if (!bDisabledFirst
2387 && !pPD->GetMaster().GetFooter().GetFooterFormat())
2388 pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2389 if (bUseLeft)
2390 pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2391 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2392 pPD->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2393 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2395 else
2397 m_bIsHeader = true;
2398 //#i17196# Cannot have left without right
2399 if (!bDisabledFirst
2400 && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2401 pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2402 if (bUseLeft)
2403 pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2404 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2405 pPD->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2406 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2409 if (bOk)
2411 bool bHackRequired = false;
2412 if (m_bIsHeader && rSection.IsFixedHeightHeader())
2413 bHackRequired = true;
2414 else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2415 bHackRequired = true;
2417 if (bHackRequired)
2419 Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2420 static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2422 else
2423 Read_HdFtText(nStart, nLen, pHdFtFormat);
2425 else if (!bOk && pPrev)
2426 CopyPageDescHdFt(pPrev, pPD, nI);
2428 m_bIsHeader = m_bIsFooter = false;
2434 bool wwSectionManager::SectionIsProtected(const wwSection &rSection) const
2436 return (mrReader.m_pWwFib->m_fReadOnlyRecommended && !rSection.IsNotProtected());
2439 void wwSectionManager::SetHdFt(wwSection &rSection, int nSect,
2440 const wwSection *pPrevious)
2442 // Header/Footer not present
2443 if (!rSection.maSep.grpfIhdt)
2444 return;
2446 OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2447 if (rSection.mpPage)
2449 mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2450 rSection);
2453 // Header/Footer - Update Index
2454 // So that the index is still valid later on
2455 if (mrReader.m_pHdFt)
2456 mrReader.m_pHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2460 void SwWW8ImplReader::AppendTextNode(SwPosition& rPos)
2462 SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
2464 const SwNumRule* pRule = nullptr;
2466 if (pText != nullptr)
2467 pRule = sw::util::GetNumRuleFromTextNode(*pText);
2469 if (
2470 pRule && !m_pWDop->fDontUseHTMLAutoSpacing &&
2471 (m_bParaAutoBefore || m_bParaAutoAfter)
2474 // If after spacing is set to auto, set the after space to 0
2475 if (m_bParaAutoAfter)
2476 SetLowerSpacing(*m_pPaM, 0);
2478 // If the previous textnode had numbering and
2479 // and before spacing is set to auto, set before space to 0
2480 if(m_pPrevNumRule && m_bParaAutoBefore)
2481 SetUpperSpacing(*m_pPaM, 0);
2483 // If the previous numbering rule was different we need
2484 // to insert a space after the previous paragraph
2485 if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2486 SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_pWDop->fDontUseHTMLAutoSpacing));
2488 // cache current paragraph
2489 if(m_pPreviousNumPaM)
2491 delete m_pPreviousNumPaM;
2492 m_pPreviousNumPaM = nullptr;
2495 m_pPreviousNumPaM = new SwPaM(*m_pPaM, m_pPaM);
2496 m_pPrevNumRule = pRule;
2498 else if(!pRule && m_pPreviousNumPaM)
2500 // If the previous paragraph has numbering but the current one does not
2501 // we need to add a space after the previous paragraph
2502 SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_pWDop->fDontUseHTMLAutoSpacing));
2503 delete m_pPreviousNumPaM;
2504 m_pPreviousNumPaM = nullptr;
2505 m_pPrevNumRule = nullptr;
2507 else
2509 // clear paragraph cache
2510 if(m_pPreviousNumPaM)
2512 delete m_pPreviousNumPaM;
2513 m_pPreviousNumPaM = nullptr;
2515 m_pPrevNumRule = pRule;
2518 // If this is the first paragraph in the document and
2519 // Auto-spacing before paragraph is set,
2520 // set the upper spacing value to 0
2521 if(m_bParaAutoBefore && m_bFirstPara && !m_pWDop->fDontUseHTMLAutoSpacing)
2522 SetUpperSpacing(*m_pPaM, 0);
2524 m_bFirstPara = false;
2526 m_rDoc.getIDocumentContentOperations().AppendTextNode(rPos);
2528 // We can flush all anchored graphics at the end of a paragraph.
2529 m_pAnchorStck->Flush();
2532 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2534 bool bRet = false;
2535 const SwPosition* pSpacingPos = rMyPam.GetPoint();
2537 const SvxULSpaceItem* pULSpaceItem = static_cast<const SvxULSpaceItem*>(m_pCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE));
2539 if(pULSpaceItem != nullptr)
2541 SvxULSpaceItem aUL(*pULSpaceItem);
2543 if(bIsUpper)
2544 aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2545 else
2546 aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2548 const sal_Int32 nEnd = pSpacingPos->nContent.GetIndex();
2549 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), 0);
2550 m_pCtrlStck->NewAttr(*pSpacingPos, aUL);
2551 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), nEnd);
2552 m_pCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2553 bRet = true;
2555 return bRet;
2558 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2560 return SetSpacing(rMyPam, nSpace, false);
2563 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2565 return SetSpacing(rMyPam, nSpace, true);
2568 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2570 if (m_bVer67)
2571 return 25;
2572 return nLevel ? 0x244C : 0x2417;
2575 void SwWW8ImplReader::EndSpecial()
2577 // Frame/Table/Anl
2578 if (m_bAnl)
2579 StopAllAnl(); // -> bAnl = false
2581 while(m_aApos.size() > 1)
2583 StopTable();
2584 m_aApos.pop_back();
2585 --m_nInTable;
2586 if (m_aApos[m_nInTable])
2587 StopApo();
2590 if (m_aApos[0])
2591 StopApo();
2593 OSL_ENSURE(!m_nInTable, "unclosed table!");
2596 bool SwWW8ImplReader::FloatingTableConversion(WW8PLCFx_Cp_FKP* pPap)
2598 // This is ww8 version of the code deciding if the table needs to be
2599 // in a floating frame.
2600 // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2601 // writerfilter/source/dmapper/PropertyMap.cxx
2602 // The two should do ~same, so if you make changes here, please check
2603 // that the other is in sync.
2605 // Note that this is just a list of heuristics till sw core can have a
2606 // table that is floating and can span over multiple pages at the same
2607 // time.
2609 bool bResult = true;
2611 const sal_uInt8 *pRes = pPap->HasSprm(NS_sprm::LN_TDefTable);
2612 if (nullptr != pRes)
2614 bResult = false;
2615 WW8TabBandDesc aDesc;
2616 aDesc.ReadDef(false, pRes);
2617 int nTextAreaWidth = m_aSectionManager.GetTextAreaWidth();
2618 int nTableWidth = aDesc.nCenter[aDesc.nWwCols] - aDesc.nCenter[0];
2620 // It seems Word has a limit here, so that in case the table width is quite
2621 // close to the text area width, then it won't perform a wrapping, even in
2622 // case the content (e.g. an empty paragraph) would fit. The magic constant
2623 // here represents this limit.
2624 const int nMagicNumber = 469;
2626 // If the table is wider than the text area, then don't create a fly
2627 // for the table: no wrapping will be performed anyway, but multi-page
2628 // tables will be broken.
2629 if ((nTableWidth + nMagicNumber) < nTextAreaWidth)
2630 bResult = true;
2632 // If there are columns, do create a fly, as the flow of the columns
2633 // would otherwise restrict the table.
2634 if (!bResult && (m_aSectionManager.CurrentSectionColCount() >= 2))
2635 bResult = true;
2638 if (bResult)
2640 WW8PLCFxSave1 aSave;
2641 pPap->Save(aSave);
2642 if (SearchTableEnd(pPap))
2644 // Table is considered to be imported into a fly frame and we
2645 // know where the end of the table is.
2646 bool bIsUnicode;
2647 WW8_FC nFc = m_pSBase->WW8Cp2Fc(pPap->Where(), &bIsUnicode);
2648 sal_uInt64 nPos = m_pStrm->Tell();
2649 m_pStrm->Seek(nFc);
2650 sal_uInt16 nUChar = 0;
2651 if (bIsUnicode)
2652 m_pStrm->ReadUInt16(nUChar);
2653 else
2655 sal_uInt8 nChar = 0;
2656 m_pStrm->ReadUChar(nChar);
2657 nUChar = nChar;
2659 m_pStrm->Seek(nPos);
2660 if (nUChar == 0xc)
2661 // The pap after the table starts with a page break, so
2662 // there will be no wrapping around the float-table.
2663 // Request no fly in this case, so the table can properly
2664 // be a multi-page one if necessary.
2665 bResult = false;
2667 pPap->Restore(aSave);
2670 return bResult;
2673 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2675 // Frame/Table/Anl
2676 if (m_bInHyperlink)
2677 return false;
2679 rbReSync = false;
2681 OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!");
2683 // TabRowEnd
2684 bool bTableRowEnd = (m_pPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417) != nullptr );
2686 // Unfortunately, for every paragraph we need to check first whether
2687 // they contain a sprm 29 (0x261B), which starts an APO.
2688 // All other sprms then refer to that APO and not to the normal text
2689 // surrounding it.
2690 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2692 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2693 // WW: APO in Table not possible
2695 // This mean that of a Table is the content of a APO, the APO start needs
2696 // to be edited first, so that the Table remains in the APO and not the
2697 // other way around.
2698 // At the End, however, we need to edit the Table End first as the APO
2699 // must end after that Table (or else we never find the APO End).
2701 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2703 // If the Table is within an APO the TabRowEnd Area misses the
2704 // APO settings.
2705 // To not end the APO there, we do not call ProcessApo
2707 // KHZ: When there is a table inside the Apo the Apo-flags are also
2708 // missing for the 2nd, 3rd... paragraphs of each cell.
2710 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2711 // be considered, the sprm 6649 gives the level of the table
2712 sal_uInt8 nCellLevel = 0;
2714 if (m_bVer67)
2715 nCellLevel = int(nullptr != m_pPlcxMan->HasParaSprm(24));
2716 else
2718 nCellLevel = int(nullptr != m_pPlcxMan->HasParaSprm(0x2416));
2719 if (!nCellLevel)
2720 nCellLevel = int(nullptr != m_pPlcxMan->HasParaSprm(0x244B));
2724 WW8_TablePos *pTabPos=nullptr;
2725 WW8_TablePos aTabPos;
2726 if(nCellLevel && !m_bVer67)
2728 WW8PLCFxSave1 aSave;
2729 m_pPlcxMan->GetPap()->Save( aSave );
2730 rbReSync = true;
2731 WW8PLCFx_Cp_FKP* pPap = m_pPlcxMan->GetPapPLCF();
2732 WW8_CP nMyStartCp=nStartCp;
2734 if (const sal_uInt8 *pLevel = m_pPlcxMan->HasParaSprm(0x6649))
2735 nCellLevel = *pLevel;
2737 bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2739 // Bad Table, remain unchanged in level, e.g. #i19667#
2740 if (!bHasRowEnd)
2741 nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2743 if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2744 pTabPos = &aTabPos;
2746 m_pPlcxMan->GetPap()->Restore( aSave );
2749 // Then look if we are in an Apo
2751 ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2753 // Look to see if we are in a Table, but Table in foot/end note not allowed
2754 bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2756 bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2758 m_bWasTabRowEnd = false; // must be deactivated right here to prevent next
2759 // WW8TabDesc::TableCellEnd() from making nonsense
2761 if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2762 bStopTab = bStartTab = true; // Required to stop and start table
2764 // Test for Anl (Numbering) and process all events in the right order
2765 if( m_bAnl && !bTableRowEnd )
2767 const sal_uInt8* pSprm13 = m_pPlcxMan->HasParaSprm( 13 );
2768 if( pSprm13 )
2769 { // Still Anl left?
2770 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2771 if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2772 || aApo.HasStartStop() // Forced Anl end
2773 || bStopTab || bStartTab )
2775 StopAnlToRestart(nT); // Anl-Restart (= change) over sprms
2777 else
2779 NextAnlLine( pSprm13 ); // Next Anl Line
2782 else
2783 { // Regular Anl end
2784 StopAllAnl(); // Actual end
2787 if (bStopTab)
2789 StopTable();
2790 m_aApos.pop_back();
2791 --m_nInTable;
2793 if (aApo.mbStopApo)
2795 StopApo();
2796 m_aApos[m_nInTable] = false;
2799 if (aApo.mbStartApo)
2801 m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2802 // We need an ReSync after StartApo
2803 // (actually only if the Apo extends past a FKP border)
2804 rbReSync = true;
2806 if (bStartTab)
2808 WW8PLCFxSave1 aSave;
2809 m_pPlcxMan->GetPap()->Save( aSave );
2811 // Numbering for cell borders causes a crash -> no Anls in Tables
2812 if (m_bAnl)
2813 StopAllAnl();
2815 if(m_nInTable < nCellLevel)
2817 if (StartTable(nStartCp))
2818 ++m_nInTable;
2819 else
2820 break;
2821 m_aApos.push_back(false);
2824 if(m_nInTable >= nCellLevel)
2826 // We need an ReSync after StartTable
2827 // (actually only if the Apo extends past a FKP border)
2828 rbReSync = true;
2829 m_pPlcxMan->GetPap()->Restore( aSave );
2832 } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2833 return bTableRowEnd;
2836 rtl_TextEncoding SwWW8ImplReader::GetCharSetFromLanguage()
2839 #i22206#/#i52786#
2840 The (default) character set used for a run of text is the default
2841 character set for the version of Word that last saved the document.
2843 This is a bit tentative, more might be required if the concept is correct.
2844 When later version of word write older 6/95 documents the charset is
2845 correctly set in the character runs involved, so its hard to reproduce
2846 documents that require this to be sure of the process involved.
2848 const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_LANGUAGE));
2849 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2850 css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2851 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2854 rtl_TextEncoding SwWW8ImplReader::GetCJKCharSetFromLanguage()
2857 #i22206#/#i52786#
2858 The (default) character set used for a run of text is the default
2859 character set for the version of Word that last saved the document.
2861 This is a bit tentative, more might be required if the concept is correct.
2862 When later version of word write older 6/95 documents the charset is
2863 correctly set in the character runs involved, so its hard to reproduce
2864 documents that require this to be sure of the process involved.
2866 const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE));
2867 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2868 css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2869 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2872 rtl_TextEncoding SwWW8ImplReader::GetCurrentCharSet()
2875 #i2015
2876 If the hard charset is set use it, if not see if there is an open
2877 character run that has set the charset, if not then fallback to the
2878 current underlying paragraph style.
2880 rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2881 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2883 if (!m_aFontSrcCharSets.empty())
2884 eSrcCharSet = m_aFontSrcCharSets.top();
2885 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && (size_t)m_nCharFormat < m_vColl.size() )
2886 eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2887 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(m_nAktColl) && m_nAktColl < m_vColl.size())
2888 eSrcCharSet = m_vColl[m_nAktColl].GetCharSet();
2889 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2890 eSrcCharSet = GetCharSetFromLanguage();
2892 return eSrcCharSet;
2895 //Takashi Ono for CJK
2896 rtl_TextEncoding SwWW8ImplReader::GetCurrentCJKCharSet()
2899 #i2015
2900 If the hard charset is set use it, if not see if there is an open
2901 character run that has set the charset, if not then fallback to the
2902 current underlying paragraph style.
2904 rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2905 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2907 if (!m_aFontSrcCJKCharSets.empty())
2908 eSrcCharSet = m_aFontSrcCJKCharSets.top();
2909 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && (size_t)m_nCharFormat < m_vColl.size() )
2910 eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2911 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && StyleExists(m_nAktColl) && m_nAktColl < m_vColl.size())
2912 eSrcCharSet = m_vColl[m_nAktColl].GetCJKCharSet();
2913 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2914 eSrcCharSet = GetCJKCharSetFromLanguage();
2916 return eSrcCharSet;
2919 void SwWW8ImplReader::PostProcessAttrs()
2921 if (m_pPostProcessAttrsInfo != nullptr)
2923 SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2925 const SfxPoolItem * pItem = aIter.GetCurItem();
2926 if (pItem != nullptr)
2930 m_pCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2931 *pItem);
2932 m_pCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2933 pItem->Which());
2935 while (!aIter.IsAtEnd() && nullptr != (pItem = aIter.NextItem()));
2938 delete m_pPostProcessAttrsInfo;
2939 m_pPostProcessAttrsInfo = nullptr;
2944 #i9241#
2945 It appears that some documents that are in a baltic 8 bit encoding which has
2946 some undefined characters can have use made of those characters, in which
2947 case they default to CP1252. If not then its perhaps that the font encoding
2948 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2949 is always 1252.
2951 So a encoding converter that on an undefined character attempts to
2952 convert from 1252 on the undefined character
2954 std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2955 sal_Char *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2957 const sal_uInt32 nFlags =
2958 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2959 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2960 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2961 RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2963 const sal_uInt32 nFlags2 =
2964 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2965 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2966 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2967 RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2969 std::size_t nDestChars=0;
2970 std::size_t nConverted=0;
2974 sal_uInt32 nInfo = 0;
2975 sal_Size nThisConverted=0;
2977 nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2978 pIn+nConverted, nInLen-nConverted,
2979 pOut+nDestChars, nOutLen-nDestChars,
2980 nFlags, &nInfo, &nThisConverted);
2982 OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2984 nConverted += nThisConverted;
2986 if (
2987 nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED ||
2988 nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2991 sal_Size nOtherConverted;
2992 rtl_TextToUnicodeConverter hCP1252Converter =
2993 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2994 nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2995 pIn+nConverted, 1,
2996 pOut+nDestChars, nOutLen-nDestChars,
2997 nFlags2, &nInfo, &nOtherConverted);
2998 rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2999 nConverted+=1;
3001 } while (nConverted < nInLen);
3003 return nDestChars;
3006 bool SwWW8ImplReader::LangUsesHindiNumbers(sal_uInt16 nLang)
3008 bool bResult = false;
3010 switch (nLang)
3012 case 0x1401: // Arabic(Algeria)
3013 case 0x3c01: // Arabic(Bahrain)
3014 case 0xc01: // Arabic(Egypt)
3015 case 0x801: // Arabic(Iraq)
3016 case 0x2c01: // Arabic (Jordan)
3017 case 0x3401: // Arabic(Kuwait)
3018 case 0x3001: // Arabic(Lebanon)
3019 case 0x1001: // Arabic(Libya)
3020 case 0x1801: // Arabic(Morocco)
3021 case 0x2001: // Arabic(Oman)
3022 case 0x4001: // Arabic(Qatar)
3023 case 0x401: // Arabic(Saudi Arabia)
3024 case 0x2801: // Arabic(Syria)
3025 case 0x1c01: // Arabic(Tunisia)
3026 case 0x3801: // Arabic(U.A.E)
3027 case 0x2401: // Arabic(Yemen)
3028 bResult = true;
3029 break;
3030 default:
3031 break;
3034 return bResult;
3037 sal_Unicode SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar)
3039 if (nChar >= 0x0030 && nChar <= 0x0039)
3040 return nChar + 0x0630;
3042 return nChar;
3046 * Return value: true for non special chars
3048 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3050 sal_Int32 nRequestedStrLen = nEnd - rPos;
3052 OSL_ENSURE(nRequestedStrLen, "String is 0");
3053 if (nRequestedStrLen <= 0)
3054 return true;
3056 sal_Int32 nRequestedPos = m_pSBase->WW8Cp2Fc(nCpOfs+rPos, &m_bIsUnicode);
3057 bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3058 OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
3059 if (!bValidPos)
3061 // Swallow missing range, e.g. #i95550#
3062 rPos+=nRequestedStrLen;
3063 return true;
3066 std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3067 OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
3068 if (!nAvailableStrLen)
3070 // Swallow missing range, e.g. #i95550#
3071 rPos+=nRequestedStrLen;
3072 return true;
3075 sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3077 // Reset Unicode flag and correct FilePos if needed.
3078 // Note: Seek is not expensive, as we're checking inline whether or not
3079 // the correct FilePos has already been reached.
3080 const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32-1);
3082 rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3083 RTL_TEXTENCODING_MS_1252;
3084 if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932)
3087 fdo#82904
3089 Older documents exported as word 95 that use unicode aware fonts will
3090 have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3091 export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3092 pain.
3094 We will try and use a fallback encoding if the conversion from
3095 RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3096 which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3097 valid RTL_TEXTENCODING_MS_932 by chance :-(
3099 We're not the only ones that struggle with this: Here's the help from
3100 MSOffice 2003 on the topic:
3103 Earlier versions of Microsoft Word were sometimes used in conjunction with
3104 third-party language-processing add-in programs designed to support Chinese or
3105 Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3106 results in incorrect text display in more recent versions of Word.
3108 However, you can set options to convert these documents so that text is
3109 displayed correctly. On the Tools menu, click Options, and then click the
3110 General tab. In the English Word 6.0/95 documents list, select Contain Asian
3111 text (to have Word interpret the text as Asian code page data, regardless of
3112 its font) or Automatically detect Asian text (to have Word attempt to determine
3113 which parts of the text are meant to be Asian).
3116 What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3117 the language is not Japanese
3120 const SfxPoolItem * pItem = GetFormatAttr(RES_CHRATR_CJK_LANGUAGE);
3121 if (pItem != nullptr && LANGUAGE_JAPANESE != static_cast<const SvxLanguageItem *>(pItem)->GetLanguage())
3123 SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3124 eSrcCharSet = GetCharSetFromLanguage();
3127 const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3128 RTL_TEXTENCODING_MS_1252;
3130 // allocate unicode string data
3131 rtl_uString *pStr = rtl_uString_alloc(nStrLen);
3132 sal_Unicode* pBuffer = pStr->buffer;
3133 sal_Unicode* pWork = pBuffer;
3135 sal_Char* p8Bits = nullptr;
3137 rtl_TextToUnicodeConverter hConverter = nullptr;
3138 if (!m_bIsUnicode || m_bVer67)
3139 hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3141 if (!m_bIsUnicode)
3142 p8Bits = new sal_Char[nStrLen];
3144 // read the stream data
3145 sal_uInt8 nBCode = 0;
3146 sal_uInt16 nUCode;
3148 sal_uInt16 nCTLLang = 0;
3149 const SfxPoolItem * pItem = GetFormatAttr(RES_CHRATR_CTL_LANGUAGE);
3150 if (pItem != nullptr)
3151 nCTLLang = static_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
3153 sal_Int32 nL2;
3154 for( nL2 = 0; nL2 < nStrLen; ++nL2, ++pWork )
3156 if (m_bIsUnicode)
3157 m_pStrm->ReadUInt16( nUCode ); // unicode --> read 2 bytes
3158 else
3160 m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3161 nUCode = nBCode;
3164 if (m_pStrm->GetError())
3166 rPos = WW8_CP_MAX-10; // -> eof or other error
3167 rtl_freeMemory(pStr);
3168 delete [] p8Bits;
3169 return true;
3172 if ((32 > nUCode) || (0xa0 == nUCode))
3174 m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3175 break; // Special character < 32, == 0xa0 found
3178 if (m_bIsUnicode)
3180 if (!m_bVer67)
3181 *pWork = nUCode;
3182 else
3184 if (nUCode >= 0x3000) //0x8000 ?
3186 sal_Char aTest[2];
3187 aTest[0] = static_cast< sal_Char >((nUCode & 0xFF00) >> 8);
3188 aTest[1] = static_cast< sal_Char >(nUCode & 0x00FF);
3189 OUString aTemp(aTest, 2, eSrcCJKCharSet);
3190 OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory");
3191 *pWork = aTemp[0];
3193 else
3195 sal_Char cTest = static_cast< sal_Char >(nUCode & 0x00FF);
3196 Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3200 else
3201 p8Bits[nL2] = nBCode;
3204 if (nL2)
3206 const sal_Int32 nEndUsed = !m_bIsUnicode
3207 ? Custom8BitToUnicode(hConverter, p8Bits, nL2, pBuffer, nStrLen)
3208 : nL2;
3210 for( sal_Int32 nI = 0; nI < nStrLen; ++nI, ++pBuffer )
3211 if (m_bRegardHindiDigits && m_bBidi && LangUsesHindiNumbers(nCTLLang))
3212 *pBuffer = TranslateToHindiNumbers(*pBuffer);
3214 pStr->buffer[nEndUsed] = 0;
3215 pStr->length = nEndUsed;
3217 emulateMSWordAddTextToParagraph(OUString(pStr, SAL_NO_ACQUIRE));
3218 pStr = nullptr;
3219 rPos += nL2;
3220 if (!m_aApos.back()) // a para end in apo doesn't count
3221 m_bWasParaEnd = false; // No CR
3224 if (hConverter)
3225 rtl_destroyTextToUnicodeConverter(hConverter);
3226 if (pStr)
3227 rtl_uString_release(pStr);
3228 delete [] p8Bits;
3229 return nL2 >= nStrLen;
3232 #define MSASCII SAL_MAX_INT16
3234 namespace
3236 // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3237 sal_Int16 lcl_getScriptType(
3238 const uno::Reference<i18n::XBreakIterator>& rBI,
3239 const OUString &rString, sal_Int32 nPos)
3241 sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3242 if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3243 nScript = MSASCII;
3244 return nScript;
3247 // We want to know about WEAK segments, so endOfScript isn't
3248 // useful, and see lcl_getScriptType anyway
3249 sal_Int32 lcl_endOfScript(
3250 const uno::Reference<i18n::XBreakIterator>& rBI,
3251 const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3253 while (nPos < rString.getLength())
3255 sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3256 if (nScript != nNewScript)
3257 break;
3258 ++nPos;
3260 return nPos;
3263 sal_Int32 lcl_getWriterScriptType(
3264 const uno::Reference<i18n::XBreakIterator>& rBI,
3265 const OUString &rString, sal_Int32 nPos)
3267 sal_Int16 nScript = i18n::ScriptType::WEAK;
3269 if (rString.isEmpty())
3270 return nScript;
3272 while (nPos >= 0)
3274 nScript = rBI->getScriptType(rString, nPos);
3275 if (nScript != i18n::ScriptType::WEAK)
3276 break;
3277 --nPos;
3280 return nScript;
3283 bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3285 return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3288 bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3290 // Ignoring CharSet, and ignoring unknown pitch
3291 return rA.GetFamilyName() == rB.GetFamilyName() &&
3292 rA.GetStyleName() == rB.GetStyleName() &&
3293 rA.GetFamily() == rB.GetFamily() &&
3294 samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3298 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3299 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3300 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3301 // hint as to which way to bias those shared characters.
3303 // That's four categories, we however have three categories. Given that problem
3304 // here we would ideally find out "what would word do" to see what font/language
3305 // word would assign to characters based on the unicode range they fall into and
3306 // hack the word one onto the range we use. However it's unclear what word's
3307 // categorization is. So we don't do that here yet.
3309 // Additional to the categorization, when word encounters weak text for ambiguous
3310 // chars it uses idcthint to indicate which way to bias. We don't have a idcthint
3311 // feature in writer.
3313 // So what we currently do here then is to split our text into non-weak/weak
3314 // sections and uses word's idcthint to determine what font it would use and
3315 // force that on for the segment. Following what we *do* know about word's
3316 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3317 // word, something we map to LATIN, so we consider all weaks chars in that range
3318 // to auto-bias to LATIN.
3320 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3321 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString& rAddString)
3323 if (rAddString.isEmpty())
3324 return;
3326 uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3327 if (!xBI.is())
3329 simpleAddTextToParagraph(rAddString);
3330 return;
3333 sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3334 sal_Int32 nLen = rAddString.getLength();
3336 OUString sParagraphText;
3337 const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3338 const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3339 if (pNd)
3340 sParagraphText = pNd->GetText();
3341 sal_Int32 nParaOffset = sParagraphText.getLength();
3342 sParagraphText = sParagraphText + rAddString;
3344 sal_Int32 nPos = 0;
3345 while (nPos < nLen)
3347 sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3348 if (nEnd < 0)
3349 break;
3351 OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3352 const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3353 const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3354 bool aForced[] = {false, false, false};
3356 int nLclIdctHint = 0xFF;
3357 if (nScript == i18n::ScriptType::WEAK)
3359 const SfxInt16Item *pIdctHint = static_cast<const SfxInt16Item*>(GetFormatAttr(RES_CHRATR_IDCTHINT));
3360 nLclIdctHint = pIdctHint->GetValue();
3362 else if (nScript == MSASCII) // Force weak chars in ascii range to use LATIN font
3363 nLclIdctHint = 0;
3365 sal_uInt16 nForceFromFontId = 0;
3366 if (nLclIdctHint != 0xFF)
3368 switch (nLclIdctHint)
3370 case 0:
3371 nForceFromFontId = RES_CHRATR_FONT;
3372 break;
3373 case 1:
3374 nForceFromFontId = RES_CHRATR_CJK_FONT;
3375 break;
3376 case 2:
3377 nForceFromFontId = RES_CHRATR_CTL_FONT;
3378 break;
3379 default:
3380 break;
3384 if (nForceFromFontId != 0)
3386 // Now we know that word would use the nForceFromFontId font for this range
3387 // Try and determine what script writer would assign this range to
3389 sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3390 nPos + nParaOffset);
3392 bool bWriterWillUseSameFontAsWordAutomatically = false;
3394 if (nWriterScript != i18n::ScriptType::WEAK)
3396 if (
3397 (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3398 (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3399 (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3402 bWriterWillUseSameFontAsWordAutomatically = true;
3404 else
3406 const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3407 sal_uInt16 nDestId = aIds[nWriterScript-1];
3408 const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(nDestId));
3409 bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3413 // Writer won't use the same font as word, so force the issue
3414 if (!bWriterWillUseSameFontAsWordAutomatically)
3416 const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3418 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3420 const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(aIds[i]));
3421 aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3422 if (aForced[i])
3424 pOverriddenItems[i] =
3425 static_cast<const SvxFontItem*>(m_pCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3427 SvxFontItem aForceFont(*pSourceFont);
3428 aForceFont.SetWhich(aIds[i]);
3429 m_pCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3435 simpleAddTextToParagraph(sChunk);
3437 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3439 if (aForced[i])
3441 m_pCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3442 if (pOverriddenItems[i])
3443 m_pCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3447 nPos = nEnd;
3448 if (nPos < nLen)
3449 nScript = lcl_getScriptType(xBI, rAddString, nPos);
3453 void SwWW8ImplReader::simpleAddTextToParagraph(const OUString& rAddString)
3455 if (rAddString.isEmpty())
3456 return;
3458 #if OSL_DEBUG_LEVEL > 1
3460 OString sText(OUStringToOString(rAddString, RTL_TEXTENCODING_UTF8));
3461 SAL_INFO("sw.ww8", "<addTextToParagraph>" << sText.getStr() << "</addTextToParagraph>");
3463 #endif
3465 const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3466 const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3468 OSL_ENSURE(pNd, "What the hell, where's my text node");
3470 if (!pNd)
3471 return;
3473 const sal_Int32 nCharsLeft = SAL_MAX_INT32 - pNd->GetText().getLength();
3474 if (nCharsLeft > 0)
3476 if (rAddString.getLength() <= nCharsLeft)
3478 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString);
3480 else
3482 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString.copy(0, nCharsLeft));
3483 AppendTextNode(*m_pPaM->GetPoint());
3484 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString.copy(nCharsLeft));
3487 else
3489 AppendTextNode(*m_pPaM->GetPoint());
3490 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString);
3493 m_bReadTable = false;
3497 * Return value: true for para end
3499 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, long nTextEnd,
3500 long nCpOfs)
3502 long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3504 if (m_bSymbol || m_bIgnoreText)
3506 if( m_bSymbol ) // Insert special chars
3508 for(sal_uInt16 nCh = 0; nCh < nEnd - rPos; ++nCh)
3510 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(m_cSymbol) );
3512 m_pCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
3513 m_pCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CJK_FONT );
3514 m_pCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CTL_FONT );
3516 m_pStrm->SeekRel( nEnd- rPos );
3517 rPos = nEnd; // Ignore until attribute end
3518 return false;
3521 while (true)
3523 if (ReadPlainChars(rPos, nEnd, nCpOfs))
3524 return false; // Done
3526 bool bStartLine = ReadChar(rPos, nCpOfs);
3527 rPos++;
3528 if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3530 return bStartLine;
3535 bool SwWW8ImplReader::HandlePageBreakChar()
3537 bool bParaEndAdded = false;
3538 // #i1909# section/page breaks should not occur in tables, word
3539 // itself ignores them in this case.
3540 if (!m_nInTable)
3542 bool IsTemp=true;
3543 SwTextNode* pTemp = m_pPaM->GetNode().GetTextNode();
3544 if (pTemp && pTemp->GetText().isEmpty()
3545 && (m_bFirstPara || m_bFirstParaOfPage))
3547 IsTemp = false;
3548 AppendTextNode(*m_pPaM->GetPoint());
3549 pTemp->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE));
3552 m_bPgSecBreak = true;
3553 m_pCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3555 If it's a 0x0c without a paragraph end before it, act like a
3556 paragraph end, but nevertheless, numbering (and perhaps other
3557 similar constructs) do not exist on the para.
3559 if (!m_bWasParaEnd && IsTemp)
3561 bParaEndAdded = true;
3562 if (0 >= m_pPaM->GetPoint()->nContent.GetIndex())
3564 if (SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode())
3566 pTextNode->SetAttr(
3567 *GetDfltAttr(RES_PARATR_NUMRULE));
3572 return bParaEndAdded;
3575 bool SwWW8ImplReader::ReadChar(long nPosCp, long nCpOfs)
3577 bool bNewParaEnd = false;
3578 // Reset Unicode flag and correct FilePos if needed.
3579 // Note: Seek is not expensive, as we're checking inline whether or not
3580 // the correct FilePos has already been reached.
3581 std::size_t nRequestedPos = m_pSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3582 if (!checkSeek(*m_pStrm, nRequestedPos))
3583 return false;
3585 sal_uInt8 nBCode(0);
3586 sal_uInt16 nWCharVal(0);
3587 if( m_bIsUnicode )
3588 m_pStrm->ReadUInt16( nWCharVal ); // unicode --> read 2 bytes
3589 else
3591 m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3592 nWCharVal = nBCode;
3595 sal_Unicode cInsert = '\x0';
3596 bool bParaMark = false;
3598 if ( 0xc != nWCharVal )
3599 m_bFirstParaOfPage = false;
3601 switch (nWCharVal)
3603 case 0:
3605 // Page number
3606 SwPageNumberField aField(
3607 static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3608 RES_PAGENUMBERFLD )), PG_RANDOM, SVX_NUM_ARABIC);
3609 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SwFormatField(aField));
3611 break;
3612 case 0xe:
3613 // if there is only one column word treats a column break like a pagebreak.
3614 if (m_aSectionManager.CurrentSectionColCount() < 2)
3615 bParaMark = HandlePageBreakChar();
3616 else if (!m_nInTable)
3618 // Always insert a txtnode for a column break, e.g. ##
3619 SwContentNode *pCntNd=m_pPaM->GetContentNode();
3620 if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3621 AppendTextNode(*m_pPaM->GetPoint());
3622 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
3624 break;
3625 case 0x7:
3627 bNewParaEnd = true;
3628 WW8PLCFxDesc* pPap = m_pPlcxMan->GetPap();
3629 //The last paragraph of each cell is terminated by a special
3630 //paragraph mark called a cell mark. Following the cell mark
3631 //that ends the last cell of a table row, the table row is
3632 //terminated by a special paragraph mark called a row mark
3634 //So the 0x7 should be right at the end of the previous
3635 //range to be a real cell-end.
3636 if (pPap->nOrigStartPos == nPosCp+1 ||
3637 pPap->nOrigStartPos == WW8_CP_MAX)
3639 TabCellEnd(); // Table cell/row end
3641 else
3642 bParaMark = true;
3644 break;
3645 case 0xf:
3646 if( !m_bSpec ) // "Satellite"
3647 cInsert = sal_Unicode('\xa4');
3648 break;
3649 case 0x14:
3650 if( !m_bSpec ) // "Para End" char
3651 cInsert = sal_Unicode('\xb5');
3652 break;
3653 case 0x15:
3654 if( !m_bSpec ) // Juristenparagraph
3656 cp_set::iterator aItr = m_aTOXEndCps.find((WW8_CP)nPosCp);
3657 if (aItr == m_aTOXEndCps.end())
3658 cInsert = sal_Unicode('\xa7');
3659 else
3660 m_aTOXEndCps.erase(aItr);
3662 break;
3663 case 0x9:
3664 cInsert = '\x9'; // Tab
3665 break;
3666 case 0xb:
3667 cInsert = '\xa'; // Hard NewLine
3668 break;
3669 case 0xc:
3670 bParaMark = HandlePageBreakChar();
3671 break;
3672 case 0x1e: // Non-breaking hyphen
3673 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDHYPHEN) );
3674 break;
3675 case 0x1f: // Non-required hyphens
3676 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_SOFTHYPHEN) );
3677 break;
3678 case 0xa0: // Non-breaking spaces
3679 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDBLANK) );
3680 break;
3681 case 0x1:
3683 Current thinking is that if bObj is set then we have a
3684 straightforward "traditional" ole object, otherwise we have a
3685 graphic preview of an associated ole2 object (or a simple
3686 graphic of course)
3688 normally in the canvas field, the code is 0x8 0x1.
3689 in a special case, the code is 0x1 0x1, which yields a simple picture
3692 bool bReadObj = IsInlineEscherHack();
3693 if( bReadObj )
3695 long nCurPos = m_pStrm->Tell();
3696 sal_uInt16 nWordCode(0);
3698 if( m_bIsUnicode )
3699 m_pStrm->ReadUInt16( nWordCode );
3700 else
3702 sal_uInt8 nByteCode(0);
3703 m_pStrm->ReadUChar( nByteCode );
3704 nWordCode = nByteCode;
3706 if( nWordCode == 0x1 )
3707 bReadObj = false;
3708 m_pStrm->Seek( nCurPos );
3710 if( !bReadObj )
3712 SwFrameFormat *pResult = nullptr;
3713 if (m_bObj)
3714 pResult = ImportOle();
3715 else if (m_bSpec)
3716 pResult = ImportGraf();
3718 // If we have a bad 0x1 insert a space instead.
3719 if (!pResult)
3721 cInsert = ' ';
3722 OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,
3723 "WW8: Please report this document, it may have a "
3724 "missing graphic");
3726 else
3728 // reset the flags.
3729 m_bObj = m_bEmbeddObj = false;
3730 m_nObjLocFc = 0;
3734 break;
3735 case 0x8:
3736 if( !m_bObj )
3737 Read_GrafLayer( nPosCp );
3738 break;
3739 case 0xd:
3740 bNewParaEnd = bParaMark = true;
3741 if (m_nInTable > 1)
3744 #i9666#/#i23161#
3745 Yes complex, if there is an entry in the undocumented PLCF
3746 which I believe to be a record of cell and row boundaries
3747 see if the magic bit which I believe to mean cell end is
3748 set. I also think btw that the third byte of the 4 byte
3749 value is the level of the cell
3751 WW8PLCFspecial* pTest = m_pPlcxMan->GetMagicTables();
3752 if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3753 pTest->Where() == nPosCp+1+nCpOfs)
3755 WW8_FC nPos;
3756 void *pData;
3757 pTest->Get(nPos, pData);
3758 sal_uInt32 nData = SVBT32ToUInt32(*static_cast<SVBT32*>(pData));
3759 if (nData & 0x2) // Might be how it works
3761 TabCellEnd();
3762 bParaMark = false;
3765 // tdf#106799: We expect TTP marks to be also cell marks,
3766 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3767 else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3769 TabCellEnd();
3770 bParaMark = false;
3774 m_bWasTabCellEnd = false;
3776 break; // line end
3777 case 0x5: // Annotation reference
3778 case 0x13:
3779 break;
3780 case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3781 if (!m_aFootnoteStack.empty())
3782 cInsert = 0x2;
3783 break;
3784 default:
3785 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3786 break;
3789 if( '\x0' != cInsert )
3791 OUString sInsert(cInsert);
3792 emulateMSWordAddTextToParagraph(sInsert);
3794 if (!m_aApos.back()) // a para end in apo doesn't count
3795 m_bWasParaEnd = bNewParaEnd;
3796 return bParaMark;
3799 void SwWW8ImplReader::ProcessAktCollChange(WW8PLCFManResult& rRes,
3800 bool* pStartAttr, bool bCallProcessSpecial)
3802 sal_uInt16 nOldColl = m_nAktColl;
3803 m_nAktColl = m_pPlcxMan->GetColl();
3805 // Invalid Style-Id
3806 if (m_nAktColl >= m_vColl.size() || !m_vColl[m_nAktColl].m_pFormat || !m_vColl[m_nAktColl].m_bColl)
3808 m_nAktColl = 0;
3809 m_bParaAutoBefore = false;
3810 m_bParaAutoAfter = false;
3812 else
3814 m_bParaAutoBefore = m_vColl[m_nAktColl].m_bParaAutoBefore;
3815 m_bParaAutoAfter = m_vColl[m_nAktColl].m_bParaAutoAfter;
3818 if (nOldColl >= m_vColl.size())
3819 nOldColl = 0; // guess! TODO make sure this is what we want
3821 bool bTabRowEnd = false;
3822 if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3824 bool bReSync;
3825 // Frame/Table/Autonumbering List Level
3826 bTabRowEnd = ProcessSpecial(bReSync, rRes.nAktCp+m_pPlcxMan->GetCpOfs());
3827 if( bReSync )
3828 *pStartAttr = m_pPlcxMan->Get( &rRes ); // Get Attribut-Pos again
3831 if (!bTabRowEnd && StyleExists(m_nAktColl))
3833 SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[ m_nAktColl ]);
3834 ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nAktColl ].m_n81Flags);
3835 ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3836 m_vColl[m_nAktColl].m_n81BiDiFlags);
3840 long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, long nTextEnd, bool& rbStartLine)
3842 long nSkipChars = 0;
3843 WW8PLCFManResult aRes;
3845 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3846 bool bStartAttr = m_pPlcxMan->Get(&aRes); // Get Attribute position again
3847 aRes.nAktCp = rTextPos; // Current Cp position
3849 bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3850 if ( bNewSection ) // New Section
3852 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3853 // Create PageDesc and fill it
3854 m_aSectionManager.CreateSep(rTextPos, m_bPgSecBreak);
3855 // -> 0xc was a Sectionbreak, but not a Pagebreak;
3856 // Create PageDesc and fill it
3857 m_bPgSecBreak = false;
3858 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3861 // New paragraph over Plcx.Fkp.papx
3862 if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3864 ProcessAktCollChange( aRes, &bStartAttr,
3865 MAN_MASK_NEW_PAP == (aRes.nFlags & MAN_MASK_NEW_PAP) &&
3866 !m_bIgnoreText );
3867 rbStartLine = false;
3870 // position of last CP that's to be ignored
3871 long nSkipPos = -1;
3873 if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3875 if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3877 if( bStartAttr ) // WW attributes
3879 if( aRes.nMemLen >= 0 )
3880 ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3882 else
3883 EndSprm( aRes.nSprmId ); // Switch off Attr
3885 else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3887 if (bStartAttr)
3889 nSkipChars = ImportExtSprm(&aRes);
3890 if (
3891 (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3892 (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3895 WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3896 // Skip Field/Footnote-/End-Note here
3897 rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3898 nSkipPos = rTextPos-1;
3901 else
3902 EndExtSprm( aRes.nSprmId );
3906 sal_Int32 nRequestedPos = m_pSBase->WW8Cp2Fc(m_pPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3907 bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3908 SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3910 // Find next Attr position (and Skip attributes of field contents if needed)
3911 if (nSkipChars && !m_bIgnoreText)
3912 m_pCtrlStck->MarkAllAttrsOld();
3913 bool bOldIgnoreText = m_bIgnoreText;
3914 m_bIgnoreText = true;
3915 sal_uInt16 nOldColl = m_nAktColl;
3916 bool bDoPlcxManPlusPLus = true;
3917 long nNext;
3920 if( bDoPlcxManPlusPLus )
3921 m_pPlcxMan->advance();
3922 nNext = bValidPos ? m_pPlcxMan->Where() : nTextEnd;
3924 if (m_pPostProcessAttrsInfo &&
3925 m_pPostProcessAttrsInfo->mnCpStart == nNext)
3927 m_pPostProcessAttrsInfo->mbCopy = true;
3930 if( (0 <= nNext) && (nSkipPos >= nNext) )
3932 nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3933 bDoPlcxManPlusPLus = false;
3934 m_bIgnoreText = true;
3937 if (m_pPostProcessAttrsInfo &&
3938 nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3940 m_pPostProcessAttrsInfo->mbCopy = false;
3943 while( nSkipPos >= nNext );
3944 m_bIgnoreText = bOldIgnoreText;
3945 if( nSkipChars )
3947 m_pCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3948 if( nOldColl != m_pPlcxMan->GetColl() )
3949 ProcessAktCollChange(aRes, nullptr, false);
3952 return nNext;
3955 //Revised 2012.8.16 for the complex attribute presentation of 0x0D in MS
3956 bool SwWW8ImplReader::IsParaEndInCPs(sal_Int32 nStart, sal_Int32 nEnd,bool bSdOD) const
3958 //Revised for performance consideration
3959 if (nStart == -1 || nEnd == -1 || nEnd < nStart )
3960 return false;
3962 for (cp_vector::const_reverse_iterator aItr = m_aEndParaPos.rbegin(); aItr!= m_aEndParaPos.rend(); ++aItr)
3964 //Revised 2012.8.16,to the 0x0D,the attribute will have two situations
3965 //*********within***********exact******
3966 //*********but also sample with only left and the position of 0x0d is the edge of the right side***********
3967 if ( bSdOD && ( (nStart < *aItr && nEnd > *aItr) || ( nStart == nEnd && *aItr == nStart)) )
3968 return true;
3969 else if ( !bSdOD && (nStart < *aItr && nEnd >= *aItr) )
3970 return true;
3973 return false;
3976 //Clear the para end position recorded in reader intermittently for the least impact on loading performance
3977 void SwWW8ImplReader::ClearParaEndPosition()
3979 if ( m_aEndParaPos.size() > 0 )
3980 m_aEndParaPos.clear();
3983 void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, long nTextEnd, bool& rbStartLine)
3985 // Dow we have attributes?
3986 if( rTextPos >= rNext )
3990 m_aCurrAttrCP = rTextPos;
3991 rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3992 if (rTextPos == rNext && rTextPos >= nTextEnd)
3993 break;
3995 while( rTextPos >= rNext );
3998 else if ( rbStartLine )
4000 /* No attributes, but still a new line.
4001 * If a line ends with a line break and paragraph attributes or paragraph templates
4002 * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
4003 * is false.
4004 * Due to this we need to set the template here as a kind of special treatment.
4006 if (!m_bCpxStyle && m_nAktColl < m_vColl.size())
4007 SetTextFormatCollAndListLevel(*m_pPaM, m_vColl[m_nAktColl]);
4008 rbStartLine = false;
4013 * CloseAttrEnds to only read the attribute ends at the end of a text or a
4014 * text area (Header, Footnote, ...).
4015 * We ignore attribute starts and fields.
4017 void SwWW8ImplReader::CloseAttrEnds()
4019 // If there are any unclosed sprms then copy them to
4020 // another stack and close the ones that must be closed
4021 std::stack<sal_uInt16> aStack;
4022 m_pPlcxMan->TransferOpenSprms(aStack);
4024 while (!aStack.empty())
4026 sal_uInt16 nSprmId = aStack.top();
4027 if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
4028 EndSprm(nSprmId);
4029 aStack.pop();
4032 EndSpecial();
4035 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4037 bool bJoined=false;
4039 bool bStartLine = true;
4040 short nCrCount = 0;
4041 short nDistance = 0;
4043 m_bWasParaEnd = false;
4044 m_nAktColl = 0;
4045 m_pAktItemSet = nullptr;
4046 m_nCharFormat = -1;
4047 m_bSpec = false;
4048 m_bPgSecBreak = false;
4050 m_pPlcxMan = new WW8PLCFMan( m_pSBase, nType, nStartCp );
4051 long nCpOfs = m_pPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4053 WW8_CP nNext = m_pPlcxMan->Where();
4054 m_pPreviousNode = nullptr;
4055 sal_uInt8 nDropLines = 0;
4056 SwCharFormat* pNewSwCharFormat = nullptr;
4057 const SwCharFormat* pFormat = nullptr;
4058 m_pStrm->Seek( m_pSBase->WW8Cp2Fc( nStartCp + nCpOfs, &m_bIsUnicode ) );
4060 WW8_CP l = nStartCp;
4061 const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4062 if (nTextLen > nMaxPossible)
4064 SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long");
4065 nTextLen = nMaxPossible;
4067 WW8_CP nTextEnd = nStartCp+nTextLen;
4068 while (l < nTextEnd)
4070 ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4071 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
4073 if (m_pPostProcessAttrsInfo != nullptr)
4074 PostProcessAttrs();
4076 if (l >= nTextEnd)
4077 break;
4079 bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4081 // If the previous paragraph was a dropcap then do not
4082 // create a new txtnode and join the two paragraphs together
4083 if (bStartLine && !m_pPreviousNode) // Line end
4085 bool bSplit = true;
4086 if (m_bCareFirstParaEndInToc)
4088 m_bCareFirstParaEndInToc = false;
4089 if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4090 bSplit = false;
4092 if (m_bCareLastParaEndInToc)
4094 m_bCareLastParaEndInToc = false;
4095 if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4096 bSplit = false;
4098 if (bSplit)
4100 // We will record the CP of a paragraph end ('0x0D'), if current loading contents is from main stream;
4101 if (m_bOnLoadingMain)
4102 m_aEndParaPos.push_back(l-1);
4103 AppendTextNode(*m_pPaM->GetPoint());
4107 if (m_pPreviousNode && bStartLine)
4109 SwTextNode* pEndNd = m_pPaM->GetNode().GetTextNode();
4110 const sal_Int32 nDropCapLen = m_pPreviousNode->GetText().getLength();
4112 // Need to reset the font size and text position for the dropcap
4114 SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4115 m_pCtrlStck->Delete(aTmp);
4118 // Get the default document dropcap which we can use as our template
4119 const SwFormatDrop* defaultDrop =
4120 static_cast<const SwFormatDrop*>( GetFormatAttr(RES_PARATR_DROP));
4121 SwFormatDrop aDrop(*defaultDrop);
4123 aDrop.GetLines() = nDropLines;
4124 aDrop.GetDistance() = nDistance;
4125 aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4126 // Word has no concept of a "whole word dropcap"
4127 aDrop.GetWholeWord() = false;
4129 if (pFormat)
4130 aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4131 else if(pNewSwCharFormat)
4132 aDrop.SetCharFormat(pNewSwCharFormat);
4134 SwPosition aStart(*pEndNd);
4135 m_pCtrlStck->NewAttr(aStart, aDrop);
4136 m_pCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4137 m_pPreviousNode = nullptr;
4139 else if (m_bDropCap)
4141 // If we have found a dropcap store the textnode
4142 m_pPreviousNode = m_pPaM->GetNode().GetTextNode();
4144 const sal_uInt8 *pDCS;
4146 if (m_bVer67)
4147 pDCS = m_pPlcxMan->GetPapPLCF()->HasSprm(46);
4148 else
4149 pDCS = m_pPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4151 if (pDCS)
4152 nDropLines = (*pDCS) >> 3;
4153 else // There is no Drop Cap Specifier hence no dropcap
4154 m_pPreviousNode = nullptr;
4156 if (const sal_uInt8 *pDistance = m_pPlcxMan->GetPapPLCF()->HasSprm(0x842F))
4157 nDistance = SVBT16ToShort( pDistance );
4158 else
4159 nDistance = 0;
4161 const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4163 if(m_pAktItemSet)
4164 pSwFormatCharFormat = &(ItemGet<SwFormatCharFormat>(*m_pAktItemSet, RES_TXTATR_CHARFMT));
4166 if(pSwFormatCharFormat)
4167 pFormat = pSwFormatCharFormat->GetCharFormat();
4169 if(m_pAktItemSet && !pFormat)
4171 OUString sPrefix(OUStringBuffer("WW8Dropcap").append(m_nDropCap++).makeStringAndClear());
4172 pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4173 m_pAktItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4174 pNewSwCharFormat->SetFormatAttr( *m_pAktItemSet );
4177 delete m_pAktItemSet;
4178 m_pAktItemSet = nullptr;
4179 m_bDropCap=false;
4182 if (bStartLine || m_bWasTabRowEnd)
4184 // Call all 64 CRs; not for Header and the like
4185 if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT)
4187 m_nProgress = (sal_uInt16)( l * 100 / nTextLen );
4188 ::SetProgressState(m_nProgress, m_pDocShell); // Update
4192 // If we have encountered a 0x0c which indicates either section of
4193 // pagebreak then look it up to see if it is a section break, and
4194 // if it is not then insert a page break. If it is a section break
4195 // it will be handled as such in the ReadAttrs of the next loop
4196 if (m_bPgSecBreak)
4198 // We need only to see if a section is ending at this cp,
4199 // the plcf will already be sitting on the correct location
4200 // if it is there.
4201 WW8PLCFxDesc aTemp;
4202 aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4203 if (m_pPlcxMan->GetSepPLCF())
4204 m_pPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4205 if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4207 // #i39251# - insert text node for page break, if no one inserted.
4208 // #i43118# - refine condition: the anchor
4209 // control stack has to have entries, otherwise it's not needed
4210 // to insert a text node.
4211 if (!bStartLine && !m_pAnchorStck->empty())
4213 AppendTextNode(*m_pPaM->GetPoint());
4215 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM,
4216 SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4217 m_bFirstParaOfPage = true;
4218 m_bPgSecBreak = false;
4223 m_pPreviousNode = nullptr;
4225 if (m_pPaM->GetPoint()->nContent.GetIndex())
4226 AppendTextNode(*m_pPaM->GetPoint());
4228 if (!m_bInHyperlink)
4229 bJoined = JoinNode(*m_pPaM);
4231 CloseAttrEnds();
4233 delete m_pPlcxMan;
4234 m_pPlcxMan = nullptr;
4235 return bJoined;
4238 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara, SotStorage* pStorage,
4239 SvStream* pSt, SwDoc& rD, const OUString& rBaseURL, bool bNewDoc, bool bSkipImages, SwPosition &rPos)
4240 : m_pDocShell(rD.GetDocShell())
4241 , m_pStg(pStorage)
4242 , m_pStrm(pSt)
4243 , m_pTableStream(nullptr)
4244 , m_pDataStream(nullptr)
4245 , m_rDoc(rD)
4246 , m_pPaM(nullptr)
4247 , m_pCtrlStck(nullptr)
4248 , m_pRedlineStack(nullptr)
4249 , m_pReffedStck(nullptr)
4250 , m_pReffingStck(nullptr)
4251 , m_pAnchorStck(nullptr)
4252 , m_aSectionManager(*this)
4253 , m_aExtraneousParas(rD)
4254 , m_aInsertedTables(rD)
4255 , m_aSectionNameGenerator(rD, OUString("WW"))
4256 , m_pSprmParser(nullptr)
4257 , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4258 , m_aParaStyleMapper(rD)
4259 , m_aCharStyleMapper(rD)
4260 , m_pFormImpl(nullptr)
4261 , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4262 , m_pFormatOfJustInsertedApo(nullptr)
4263 , m_pPreviousNumPaM(nullptr)
4264 , m_pPrevNumRule(nullptr)
4265 , m_pPostProcessAttrsInfo(nullptr)
4266 , m_pWwFib(nullptr)
4267 , m_pFonts(nullptr)
4268 , m_pWDop(nullptr)
4269 , m_pLstManager(nullptr)
4270 , m_pSBase(nullptr)
4271 , m_pPlcxMan(nullptr)
4272 , m_aTextNodesHavingFirstLineOfstSet()
4273 , m_aTextNodesHavingLeftIndentSet()
4274 , m_pStyles(nullptr)
4275 , m_pAktColl(nullptr)
4276 , m_pAktItemSet(nullptr)
4277 , m_pDfltTextFormatColl(nullptr)
4278 , m_pStandardFormatColl(nullptr)
4279 , m_pHdFt(nullptr)
4280 , m_pWFlyPara(nullptr)
4281 , m_pSFlyPara(nullptr)
4282 , m_pTableDesc(nullptr)
4283 , m_pNumOlst(nullptr)
4284 , m_pDrawModel(nullptr)
4285 , m_pDrawPg(nullptr)
4286 , m_pDrawEditEngine(nullptr)
4287 , m_pWWZOrder(nullptr)
4288 , m_pNumFieldType(nullptr)
4289 , m_pMSDffManager(nullptr)
4290 , m_pAtnNames(nullptr)
4291 , m_sBaseURL(rBaseURL)
4292 , m_nIniFlags(0)
4293 , m_nIniFlags1(0)
4294 , m_nFieldFlags(0)
4295 , m_bRegardHindiDigits( false )
4296 , m_bDrawCpOValid( false )
4297 , m_nDrawCpO(0)
4298 , m_nPicLocFc(0)
4299 , m_nObjLocFc(0)
4300 , m_nIniFlyDx(0)
4301 , m_nIniFlyDy(0)
4302 , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US)
4303 , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US)
4304 , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW)
4305 , m_nProgress(0)
4306 , m_nAktColl(0)
4307 , m_nFieldNum(0)
4308 , m_nLFOPosition(USHRT_MAX)
4309 , m_nCharFormat(0)
4310 , m_nDrawXOfs(0)
4311 , m_nDrawYOfs(0)
4312 , m_nDrawXOfs2(0)
4313 , m_nDrawYOfs2(0)
4314 , m_cSymbol(0)
4315 , m_nWantedVersion(nVersionPara)
4316 , m_nSwNumLevel(0xff)
4317 , m_nWwNumType(0xff)
4318 , m_nListLevel(WW8ListManager::nMaxLevel)
4319 , m_bNewDoc(bNewDoc)
4320 , m_bSkipImages(bSkipImages)
4321 , m_bReadNoTable(false)
4322 , m_bPgSecBreak(false)
4323 , m_bSpec(false)
4324 , m_bObj(false)
4325 , m_bTxbxFlySection(false)
4326 , m_bHasBorder(false)
4327 , m_bSymbol(false)
4328 , m_bIgnoreText(false)
4329 , m_nInTable(0)
4330 , m_bWasTabRowEnd(false)
4331 , m_bWasTabCellEnd(false)
4332 , m_bAnl(false)
4333 , m_bHdFtFootnoteEdn(false)
4334 , m_bFootnoteEdn(false)
4335 , m_bIsHeader(false)
4336 , m_bIsFooter(false)
4337 , m_bIsUnicode(false)
4338 , m_bCpxStyle(false)
4339 , m_bStyNormal(false)
4340 , m_bWWBugNormal(false)
4341 , m_bNoAttrImport(false)
4342 , m_bInHyperlink(false)
4343 , m_bWasParaEnd(false)
4344 , m_bVer67(false)
4345 , m_bVer6(false)
4346 , m_bVer7(false)
4347 , m_bVer8(false)
4348 , m_bEmbeddObj(false)
4349 , m_bAktAND_fNumberAcross(false)
4350 , m_bNoLnNumYet(true)
4351 , m_bFirstPara(true)
4352 , m_bFirstParaOfPage(false)
4353 , m_bParaAutoBefore(false)
4354 , m_bParaAutoAfter(false)
4355 , m_bDropCap(false)
4356 , m_nDropCap(0)
4357 , m_bBidi(false)
4358 , m_bReadTable(false)
4359 , m_bLoadingTOXCache(false)
4360 , m_nEmbeddedTOXLevel(0)
4361 , m_bLoadingTOXHyperlink(false)
4362 , m_pPosAfterTOC(nullptr)
4363 , m_pPreviousNode(nullptr)
4364 , m_bCareFirstParaEndInToc(false)
4365 , m_bCareLastParaEndInToc(false)
4366 , m_aTOXEndCps()
4367 , m_aCurrAttrCP(-1)
4368 , m_bOnLoadingMain(false)
4370 m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4371 m_aApos.push_back(false);
4373 mpCursor = m_rDoc.CreateUnoCursor(rPos);
4376 void SwWW8ImplReader::DeleteStack(SwFltControlStack* pStck)
4378 if( pStck )
4380 pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4381 pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4382 delete pStck;
4384 else
4386 OSL_ENSURE( false, "WW-Stack bereits geloescht" );
4390 void wwSectionManager::SetSegmentToPageDesc(const wwSection &rSection,
4391 bool bIgnoreCols)
4393 SwPageDesc &rPage = *rSection.mpPage;
4395 SetNumberingType(rSection, rPage);
4397 SwFrameFormat &rFormat = rPage.GetMaster();
4399 if(mrReader.m_pWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4400 mrReader.GrafikCtor();
4402 if (mrReader.m_pWDop->fUseBackGroundInAllmodes && mrReader.m_pMSDffManager)
4404 Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4405 SvxMSDffImportData aData(aRect);
4406 SdrObject* pObject = nullptr;
4407 if (mrReader.m_pMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4409 // Only handle shape if it is a background shape
4410 if (((*aData.begin())->nFlags & 0x400) != 0)
4412 SfxItemSet aSet(rFormat.GetAttrSet());
4413 mrReader.MatchSdrItemsIntoFlySet(pObject, aSet, mso_lineSimple,
4414 mso_lineSolid, mso_sptRectangle, aRect);
4415 rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4418 SdrObject::Free(pObject);
4420 wwULSpaceData aULData;
4421 GetPageULData(rSection, aULData);
4422 SetPageULSpaceItems(rFormat, aULData, rSection);
4424 rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4426 SetPage(rPage, rFormat, rSection, bIgnoreCols);
4428 if (!(rSection.maSep.pgbApplyTo & 1))
4429 SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4430 if (!(rSection.maSep.pgbApplyTo & 2))
4431 SwWW8ImplReader::SetPageBorder(rPage.GetFirstMaster(), rSection);
4433 mrReader.SetDocumentGrid(rFormat, rSection);
4436 void wwSectionManager::SetUseOn(wwSection &rSection)
4438 bool bMirror = mrReader.m_pWDop->fMirrorMargins ||
4439 mrReader.m_pWDop->doptypography.f2on1;
4441 UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4442 UseOnPage eUse = eUseBase;
4443 if (!mrReader.m_pWDop->fFacingPages)
4444 eUse |= UseOnPage::HeaderShare | UseOnPage::FooterShare;
4445 if (!rSection.HasTitlePage())
4446 eUse |= UseOnPage::FirstShare;
4448 OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
4449 if (rSection.mpPage)
4450 rSection.mpPage->WriteUseOn(eUse);
4454 * Set the page descriptor on this node, handle the different cases for a text
4455 * node or a table
4457 void GiveNodePageDesc(SwNodeIndex &rIdx, const SwFormatPageDesc &rPgDesc,
4458 SwDoc &rDoc)
4461 If it's a table here, apply the pagebreak to the table
4462 properties, otherwise we add it to the para at this
4463 position
4465 if (rIdx.GetNode().IsTableNode())
4467 SwTable& rTable =
4468 rIdx.GetNode().GetTableNode()->GetTable();
4469 SwFrameFormat* pApply = rTable.GetFrameFormat();
4470 OSL_ENSURE(pApply, "impossible");
4471 if (pApply)
4472 pApply->SetFormatAttr(rPgDesc);
4474 else
4476 SwPosition aPamStart(rIdx);
4477 aPamStart.nContent.Assign(
4478 rIdx.GetNode().GetContentNode(), 0);
4479 SwPaM aPage(aPamStart);
4481 rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4486 * Map a word section to a writer page descriptor
4488 SwFormatPageDesc wwSectionManager::SetSwFormatPageDesc(mySegIter &rIter,
4489 mySegIter &rStart, bool bIgnoreCols)
4491 if (mrReader.m_bNewDoc && rIter == rStart)
4493 rIter->mpPage =
4494 mrReader.m_rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD);
4496 else
4498 rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4499 SwViewShell::GetShellRes()->GetPageDescName(mnDesc, ShellResource::NORMAL_PAGE),
4500 nullptr, false);
4502 OSL_ENSURE(rIter->mpPage, "no page!");
4503 if (!rIter->mpPage)
4504 return SwFormatPageDesc();
4506 // Set page before hd/ft
4507 const wwSection *pPrevious = nullptr;
4508 if (rIter != rStart)
4509 pPrevious = &(*(rIter-1));
4510 SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4511 SetUseOn(*rIter);
4513 // Set hd/ft after set page
4514 SetSegmentToPageDesc(*rIter, bIgnoreCols);
4516 SwFormatPageDesc aRet(rIter->mpPage);
4518 rIter->mpPage->SetFollow(rIter->mpPage);
4520 if (rIter->PageRestartNo())
4521 aRet.SetNumOffset(rIter->PageStartAt());
4523 ++mnDesc;
4524 return aRet;
4527 void wwSectionManager::InsertSegments()
4529 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
4530 bool bUseEnhFields = rOpt.IsUseEnhancedFields();
4531 mySegIter aEnd = maSegments.end();
4532 mySegIter aStart = maSegments.begin();
4533 for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4535 // If the section is of type "New column" (0x01), then simply insert a column break.
4536 // But only if there actually are columns on the page, otherwise a column break
4537 // seems to be handled like a page break by MSO.
4538 if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4540 SwPaM start( aIter->maStart );
4541 mrReader.m_rDoc.getIDocumentContentOperations().InsertPoolItem( start, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
4542 continue;
4545 mySegIter aNext = aIter+1;
4546 mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4548 // If two following sections are different in following properties, Word will interprete a continuous
4549 // section break between them as if it was a section break next page.
4550 bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4551 (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4553 bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() && bThisAndPreviousAreCompatible;
4554 bool bInsertPageDesc = !bInsertSection;
4555 // HACK Force new pagedesc if margins change, otherwise e.g. floating tables may be anchored improperly.
4556 if( aIter->maSep.dyaTop != aPrev->maSep.dyaTop || aIter->maSep.dyaBottom != aPrev->maSep.dyaBottom
4557 || aIter->maSep.dxaLeft != aPrev->maSep.dxaLeft || aIter->maSep.dxaRight != aPrev->maSep.dxaRight )
4558 bInsertPageDesc = true;
4559 bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4560 if (bUseEnhFields && mrReader.m_pWDop->fProtEnabled && aIter->IsNotProtected())
4562 // here we have the special case that the whole document is protected, with the exception of this section.
4563 // I want to address this when I do the section rework, so for the moment we disable the overall protection then...
4564 mrReader.m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM, false );
4567 if (bInsertPageDesc)
4570 If a cont section follows this section then we won't be
4571 creating a page desc with 2+ cols as we cannot host a one
4572 col section in a 2+ col pagedesc and make it look like
4573 word. But if the current section actually has columns then
4574 we are forced to insert a section here as well as a page
4575 descriptor.
4578 bool bIgnoreCols = false;
4579 bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4580 ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4581 (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4582 (aIter->IsLandScape() == aNext->IsLandScape()));
4584 if (((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected))
4586 bIgnoreCols = true;
4587 if ((aIter->NoCols() > 1) || bProtected)
4588 bInsertSection = true;
4591 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4592 if (!aDesc.GetPageDesc())
4593 continue;
4595 // special case handling for odd/even section break
4596 // a) as before create a new page style for the section break
4597 // b) set Layout of generated page style to right/left ( according
4598 // to section break odd/even )
4599 // c) create a new style to follow the break page style
4600 if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4602 // SetSwFormatPageDesc calls some methods that could
4603 // modify aIter (e.g. wwSection ).
4604 // Since we call SetSwFormatPageDesc below to generate the
4605 // 'Following' style of the Break style, it is safer
4606 // to take a copy of the contents of aIter.
4607 wwSection aTmpSection = *aIter;
4608 // create a new following page style
4609 SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4610 // restore any contents of aIter trashed by SetSwFormatPageDesc
4611 *aIter = aTmpSection;
4613 // Handle the section break
4614 UseOnPage eUseOnPage = UseOnPage::Left;
4615 if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4616 eUseOnPage = UseOnPage::Right;
4618 // Keep the share flags.
4619 aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4620 aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4623 GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4626 SwTextNode* pTextNd = nullptr;
4627 if (bInsertSection)
4629 // Start getting the bounds of this section
4630 SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4631 SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4632 if (aNext != aEnd)
4634 aAnchor = aNext->maStart;
4635 aSectPaM.GetPoint()->nNode = aAnchor;
4636 aSectPaM.GetPoint()->nContent.Assign(
4637 aNext->maStart.GetNode().GetContentNode(), 0);
4638 aSectPaM.Move(fnMoveBackward);
4641 const SwPosition* pPos = aSectPaM.GetPoint();
4642 SwTextNode const*const pSttNd = pPos->nNode.GetNode().GetTextNode();
4643 const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4644 if (pTableNd)
4646 pTextNd =
4647 mrReader.m_rDoc.GetNodes().MakeTextNode(aAnchor,
4648 mrReader.m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ));
4650 aSectPaM.GetPoint()->nNode.Assign(*pTextNd);
4651 aSectPaM.GetPoint()->nContent.Assign(
4652 aSectPaM.GetContentNode(), 0);
4655 aSectPaM.SetMark();
4657 aSectPaM.GetPoint()->nNode = aIter->maStart;
4658 aSectPaM.GetPoint()->nContent.Assign(
4659 aSectPaM.GetContentNode(), 0);
4661 bool bHasOwnHdFt = false;
4663 In this nightmare scenario the continuous section has its own
4664 headers and footers so we will try and find a hard page break
4665 between here and the end of the section and put the headers and
4666 footers there.
4668 if (!bInsertPageDesc)
4670 bHasOwnHdFt =
4671 mrReader.HasOwnHeaderFooter(
4672 aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4673 aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4676 if (bHasOwnHdFt)
4678 // #i40766# Need to cache the page descriptor in case there is
4679 // no page break in the section
4680 SwPageDesc *pOrig = aIter->mpPage;
4681 bool bFailed = true;
4682 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4683 if (aDesc.GetPageDesc())
4685 sal_uLong nStart = aSectPaM.Start()->nNode.GetIndex();
4686 sal_uLong nEnd = aSectPaM.End()->nNode.GetIndex();
4687 for(; nStart <= nEnd; ++nStart)
4689 SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4690 if (!pNode)
4691 continue;
4692 if (sw::util::HasPageBreak(*pNode))
4694 SwNodeIndex aIdx(*pNode);
4695 GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4696 bFailed = false;
4697 break;
4701 if(bFailed)
4703 aIter->mpPage = pOrig;
4707 // End getting the bounds of this section, quite a job eh?
4708 SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4709 // The last section if continuous is always unbalanced
4710 if (pRet)
4712 // Set the columns to be UnBalanced if that compatibility option is set
4713 if (mrReader.m_pWDop->fNoColumnBalance)
4714 pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4715 else
4717 // Otherwise set to unbalanced if the following section is
4718 // not continuous, (which also means that the last section
4719 // is unbalanced)
4720 if (aNext == aEnd || !aNext->IsContinuous())
4721 pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4726 if (pTextNd)
4728 SwNodeIndex aIdx(*pTextNd);
4729 SwPaM aTest(aIdx);
4730 mrReader.m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4731 pTextNd = nullptr;
4736 void wwExtraneousParas::delete_all_from_doc()
4738 auto aEnd = m_aTextNodes.rend();
4739 for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4741 SwTextNode *pTextNode = *aI;
4742 SwNodeIndex aIdx(*pTextNode);
4743 SwPaM aTest(aIdx);
4744 m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4746 m_aTextNodes.clear();
4749 void SwWW8ImplReader::StoreMacroCmds()
4751 if (m_pWwFib->m_lcbCmds)
4753 m_pTableStream->Seek(m_pWwFib->m_fcCmds);
4755 uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4757 if (!xRoot.is())
4758 return;
4762 uno::Reference < io::XStream > xStream =
4763 xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4764 std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4766 sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_pWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4767 std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4768 m_pWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4769 xOutStream->WriteBytes(xBuffer.get(), m_pWwFib->m_lcbCmds);
4771 catch (...)
4777 void SwWW8ImplReader::ReadDocVars()
4779 std::vector<OUString> aDocVarStrings;
4780 std::vector<ww::bytes> aDocVarStringIds;
4781 std::vector<OUString> aDocValueStrings;
4782 WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_pWwFib->m_fcStwUser,
4783 m_pWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4784 aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4785 if (!m_bVer67) {
4786 using namespace ::com::sun::star;
4788 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4789 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4790 uno::Reference<document::XDocumentProperties> xDocProps(
4791 xDPS->getDocumentProperties());
4792 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4793 uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4794 xDocProps->getUserDefinedProperties();
4795 OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null");
4797 for(size_t i=0; i<aDocVarStrings.size(); i++)
4799 const OUString &rName = aDocVarStrings[i];
4800 uno::Any aValue;
4801 aValue <<= OUString(aDocValueStrings[i]);
4802 try {
4803 xUserDefinedProps->addProperty( rName,
4804 beans::PropertyAttribute::REMOVABLE,
4805 aValue );
4806 } catch (const uno::Exception &) {
4807 // ignore
4814 * Document Info
4816 void SwWW8ImplReader::ReadDocInfo()
4818 if( m_pStg )
4820 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4821 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4822 uno::Reference<document::XDocumentProperties> xDocProps(
4823 xDPS->getDocumentProperties());
4824 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4826 if (xDocProps.is()) {
4827 if ( m_pWwFib->m_fDot )
4829 OUString sTemplateURL;
4830 SfxMedium* pMedium = m_pDocShell->GetMedium();
4831 if ( pMedium )
4833 OUString aName = pMedium->GetName();
4834 INetURLObject aURL( aName );
4835 sTemplateURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
4836 if ( !sTemplateURL.isEmpty() )
4837 xDocProps->setTemplateURL( sTemplateURL );
4840 else if (m_pWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4842 long nCur = m_pTableStream->Tell();
4843 Sttb aSttb;
4844 m_pTableStream->Seek( m_pWwFib->m_fcSttbfAssoc ); // point at tgc record
4845 if (!aSttb.Read( *m_pTableStream ) )
4846 OSL_TRACE("** Read of SttbAssoc data failed!!!! ");
4847 m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4848 #if OSL_DEBUG_LEVEL > 1
4849 aSttb.Print( stderr );
4850 #endif
4851 OUString sPath = aSttb.getStringAtIndex( 0x1 );
4852 OUString aURL;
4853 // attempt to convert to url (won't work for obvious reasons on linux)
4854 if ( !sPath.isEmpty() )
4855 osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4856 if (aURL.isEmpty())
4857 xDocProps->setTemplateURL( aURL );
4858 else
4859 xDocProps->setTemplateURL( sPath );
4862 sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4867 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4869 if ( xPrjNameCache.is() )
4871 INetURLObject aObj;
4872 aObj.SetURL( sTemplatePathOrURL );
4873 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4874 OUString aURL;
4875 if ( bIsURL )
4876 aURL = sTemplatePathOrURL;
4877 else
4879 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4880 aObj.SetURL( aURL );
4884 OUString templateNameWithExt = aObj.GetLastName();
4885 OUString templateName;
4886 sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4887 if ( nIndex != -1 )
4889 templateName = templateNameWithExt.copy( 0, nIndex );
4890 xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4893 catch( const uno::Exception& )
4899 class WW8Customizations
4901 SvStream* mpTableStream;
4902 WW8Fib mWw8Fib;
4903 public:
4904 WW8Customizations( SvStream*, WW8Fib& );
4905 void Import( SwDocShell* pShell );
4908 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib& rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4912 void WW8Customizations::Import( SwDocShell* pShell )
4914 if ( mWw8Fib.m_lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4915 return;
4918 Tcg aTCG;
4919 long nCur = mpTableStream->Tell();
4920 mpTableStream->Seek( mWw8Fib.m_fcCmds ); // point at tgc record
4921 bool bReadResult = aTCG.Read( *mpTableStream );
4922 mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4923 if ( !bReadResult )
4925 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4926 return;
4928 #if OSL_DEBUG_LEVEL > 1
4929 aTCG.Print( stderr );
4930 #endif
4931 aTCG.ImportCustomToolBar( *pShell );
4933 catch(...)
4935 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4939 void SwWW8ImplReader::ReadGlobalTemplateSettings( const OUString& sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4941 if (utl::ConfigManager::IsAvoidConfig())
4942 return;
4944 SvtPathOptions aPathOpt;
4945 OUString aAddinPath = aPathOpt.GetAddinPath();
4946 uno::Sequence< OUString > sGlobalTemplates;
4948 // first get the autoload addins in the directory STARTUP
4949 uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4951 if( xSFA->isFolder( aAddinPath ) )
4952 sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4954 sal_Int32 nEntries = sGlobalTemplates.getLength();
4955 for ( sal_Int32 i=0; i<nEntries; ++i )
4957 INetURLObject aObj;
4958 aObj.SetURL( sGlobalTemplates[ i ] );
4959 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4960 OUString aURL;
4961 if ( bIsURL )
4962 aURL = sGlobalTemplates[ i ];
4963 else
4964 osl::FileBase::getFileURLFromSystemPath( sGlobalTemplates[ i ], aURL );
4965 if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.isEmpty() && sCreatedFrom.equals( aURL ) ) )
4966 continue; // don't try and read the same document as ourselves
4968 tools::SvRef<SotStorage> rRoot = new SotStorage( aURL, StreamMode::STD_READWRITE );
4970 BasicProjImportHelper aBasicImporter( *m_pDocShell );
4971 // Import vba via oox filter
4972 aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
4973 lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4974 // Read toolbars & menus
4975 tools::SvRef<SotStorageStream> refMainStream = rRoot->OpenSotStream( "WordDocument");
4976 refMainStream->SetEndian(SvStreamEndian::LITTLE);
4977 WW8Fib aWwFib( *refMainStream, 8 );
4978 tools::SvRef<SotStorageStream> xTableStream = rRoot->OpenSotStream(OUString::createFromAscii( aWwFib.m_fWhichTableStm ? SL::a1Table : SL::a0Table), StreamMode::STD_READ);
4980 if (xTableStream.Is() && SVSTREAM_OK == xTableStream->GetError())
4982 xTableStream->SetEndian(SvStreamEndian::LITTLE);
4983 WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
4984 aGblCustomisations.Import( m_pDocShell );
4989 sal_uLong SwWW8ImplReader::CoreLoad(WW8Glossary *pGloss)
4991 sal_uLong nErrRet = 0;
4993 m_rDoc.SetDocumentType( SwDoc::DOCTYPE_MSWORD );
4994 if (m_bNewDoc && m_pStg && !pGloss)
4996 // Initialize RDF metadata, to be able to add statements during the import.
4999 uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(m_rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW);
5000 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
5001 uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
5002 const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xStorage, m_sBaseURL));
5003 uno::Reference<task::XInteractionHandler> xHandler;
5004 xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
5006 catch (const uno::Exception& rException)
5008 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: failed to initialize RDF metadata: " << rException.Message);
5010 ReadDocInfo();
5013 ::ww8::WW8FibData * pFibData = new ::ww8::WW8FibData();
5015 if (m_pWwFib->m_fReadOnlyRecommended)
5016 pFibData->setReadOnlyRecommended(true);
5017 else
5018 pFibData->setReadOnlyRecommended(false);
5020 if (m_pWwFib->m_fWriteReservation)
5021 pFibData->setWriteReservation(true);
5022 else
5023 pFibData->setWriteReservation(false);
5025 ::sw::tExternalDataPointer pExternalFibData(pFibData);
5027 m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB, pExternalFibData);
5029 ::sw::tExternalDataPointer pSttbfAsoc
5030 (new ::ww8::WW8Sttb<ww8::WW8Struct>(*m_pTableStream, m_pWwFib->m_fcSttbfAssoc, m_pWwFib->m_lcbSttbfAssoc));
5032 m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC, pSttbfAsoc);
5034 if (m_pWwFib->m_fWriteReservation || m_pWwFib->m_fReadOnlyRecommended)
5036 SwDocShell * pDocShell = m_rDoc.GetDocShell();
5037 if (pDocShell)
5038 pDocShell->SetReadOnlyUI();
5041 m_pPaM = mpCursor.get();
5043 m_pCtrlStck = new SwWW8FltControlStack( &m_rDoc, m_nFieldFlags, *this );
5045 m_pRedlineStack = new sw::util::RedlineStack(m_rDoc);
5048 RefFieldStck: Keeps track of bookmarks which may be inserted as
5049 variables instead.
5051 m_pReffedStck = new SwWW8ReferencedFltEndStack(&m_rDoc, m_nFieldFlags);
5052 m_pReffingStck = new SwWW8FltRefStack(&m_rDoc, m_nFieldFlags);
5054 m_pAnchorStck = new SwWW8FltAnchorStack(&m_rDoc, m_nFieldFlags);
5056 size_t nPageDescOffset = m_rDoc.GetPageDescCnt();
5058 SwNodeIndex aSttNdIdx( m_rDoc.GetNodes() );
5059 SwRelNumRuleSpaces aRelNumRule(m_rDoc, m_bNewDoc);
5061 RedlineFlags eMode = RedlineFlags::ShowInsert;
5063 m_pSprmParser = new wwSprmParser(*m_pWwFib);
5065 // Set handy helper variables
5066 m_bVer6 = (6 == m_pWwFib->m_nVersion);
5067 m_bVer7 = (7 == m_pWwFib->m_nVersion);
5068 m_bVer67 = m_bVer6 || m_bVer7;
5069 m_bVer8 = (8 == m_pWwFib->m_nVersion);
5071 m_eTextCharSet = WW8Fib::GetFIBCharset(m_pWwFib->m_chse, m_pWwFib->m_lid);
5072 m_eStructCharSet = WW8Fib::GetFIBCharset(m_pWwFib->m_chseTables, m_pWwFib->m_lid);
5074 m_bWWBugNormal = m_pWwFib->m_nProduct == 0xc03d;
5076 if (!m_bNewDoc)
5077 aSttNdIdx = m_pPaM->GetPoint()->nNode;
5079 ::StartProgress(STR_STATSTR_W4WREAD, 0, 100, m_pDocShell);
5081 // read Font Table
5082 m_pFonts = new WW8Fonts( *m_pTableStream, *m_pWwFib );
5084 // Document Properties
5085 m_pWDop = new WW8Dop( *m_pTableStream, m_pWwFib->m_nFib, m_pWwFib->m_fcDop,
5086 m_pWwFib->m_lcbDop );
5088 if (m_bNewDoc)
5089 ImportDop();
5092 Import revisioning data: author names
5094 if( m_pWwFib->m_lcbSttbfRMark )
5096 ReadRevMarkAuthorStrTabl( *m_pTableStream,
5097 m_pWwFib->m_fcSttbfRMark,
5098 m_pWwFib->m_lcbSttbfRMark, m_rDoc );
5101 // Initialize our String/ID map for Linked Sections
5102 std::vector<OUString> aLinkStrings;
5103 std::vector<ww::bytes> aStringIds;
5105 WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_pWwFib->m_fcSttbFnm,
5106 m_pWwFib->m_lcbSttbFnm, m_bVer67 ? 2 : 0, m_eStructCharSet,
5107 aLinkStrings, &aStringIds);
5109 for (size_t i=0; i < aLinkStrings.size() && i < aStringIds.size(); ++i)
5111 const ww::bytes& stringId = aStringIds[i];
5112 if (stringId.size() < sizeof(WW8_STRINGID))
5114 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5115 continue;
5117 const WW8_STRINGID *stringIdStruct = reinterpret_cast<const WW8_STRINGID*>(stringId.data());
5118 m_aLinkStringMap[SVBT16ToShort(stringIdStruct->nStringId)] = aLinkStrings[i];
5121 ReadDocVars(); // import document variables as meta information.
5123 ::SetProgressState(m_nProgress, m_pDocShell); // Update
5125 m_pLstManager = new WW8ListManager( *m_pTableStream, *this );
5128 zuerst(!) alle Styles importieren (siehe WW8PAR2.CXX)
5129 VOR dem Import der Listen !!
5131 ::SetProgressState(m_nProgress, m_pDocShell); // Update
5132 m_pStyles = new WW8RStyle( *m_pWwFib, this ); // Styles
5133 m_pStyles->Import();
5136 In the end: (also see WW8PAR3.CXX)
5138 Go through all Styles and attach respective List Format
5139 AFTER we imported the Styles and AFTER we imported the Lists!
5141 ::SetProgressState(m_nProgress, m_pDocShell); // Update
5142 m_pStyles->PostProcessStyles();
5144 if (!m_vColl.empty())
5145 SetOutlineStyles();
5147 m_pSBase = new WW8ScannerBase(m_pStrm,m_pTableStream,m_pDataStream,m_pWwFib);
5149 static const SvxExtNumType eNumTA[16] =
5151 SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
5152 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N,
5153 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
5154 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
5155 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
5156 SVX_NUM_ARABIC, SVX_NUM_ARABIC
5159 if (m_pSBase->AreThereFootnotes())
5161 static const SwFootnoteNum eNumA[4] =
5163 FTNNUM_DOC, FTNNUM_CHAPTER, FTNNUM_PAGE, FTNNUM_DOC
5166 SwFootnoteInfo aInfo;
5167 aInfo = m_rDoc.GetFootnoteInfo(); // Copy-Ctor private
5169 aInfo.ePos = FTNPOS_PAGE;
5170 aInfo.eNum = eNumA[m_pWDop->rncFootnote];
5171 sal_uInt16 nfcFootnoteRef = m_pWDop->nfcFootnoteRef & 0xF;
5172 aInfo.aFormat.SetNumberingType( static_cast< sal_uInt16 >(eNumTA[nfcFootnoteRef]) );
5173 if( m_pWDop->nFootnote )
5174 aInfo.nFootnoteOffset = m_pWDop->nFootnote - 1;
5175 m_rDoc.SetFootnoteInfo( aInfo );
5177 if( m_pSBase->AreThereEndnotes() )
5179 SwEndNoteInfo aInfo;
5180 aInfo = m_rDoc.GetEndNoteInfo(); // Same as for Footnote
5181 sal_uInt16 nfcEdnRef = m_pWDop->nfcEdnRef & 0xF;
5182 aInfo.aFormat.SetNumberingType( static_cast< sal_uInt16 >(eNumTA[nfcEdnRef]) );
5183 if( m_pWDop->nEdn )
5184 aInfo.nFootnoteOffset = m_pWDop->nEdn - 1;
5185 m_rDoc.SetEndNoteInfo( aInfo );
5188 if( m_pWwFib->m_lcbPlcfhdd )
5189 m_pHdFt = new WW8PLCF_HdFt( m_pTableStream, *m_pWwFib, *m_pWDop );
5191 if (!m_bNewDoc)
5193 // inserting into an existing document:
5194 // As only complete paragraphs are inserted, the current one
5195 // needs to be splitted - once or even twice.
5196 const SwPosition* pPos = m_pPaM->GetPoint();
5198 // split current paragraph to get new paragraph for the insertion
5199 m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5201 // another split, if insertion position was not at the end of the current paragraph.
5202 SwTextNode const*const pTextNd = pPos->nNode.GetNode().GetTextNode();
5203 if ( pTextNd->GetText().getLength() )
5205 m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5206 // move PaM back to the newly empty paragraph
5207 m_pPaM->Move( fnMoveBackward );
5210 // suppress insertion of tables inside footnotes.
5211 const sal_uLong nNd = pPos->nNode.GetIndex();
5212 m_bReadNoTable = ( nNd < m_rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
5213 m_rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd );
5216 ::SetProgressState(m_nProgress, m_pDocShell); // Update
5218 // loop for each glossary entry and add dummy section node
5219 if (pGloss)
5221 WW8PLCF aPlc(*m_pTableStream, m_pWwFib->m_fcPlcfglsy, m_pWwFib->m_lcbPlcfglsy, 0);
5223 WW8_CP nStart, nEnd;
5224 void* pDummy;
5226 for (int i = 0; i < pGloss->GetNoStrings(); ++i, aPlc.advance())
5228 SwNodeIndex aIdx( m_rDoc.GetNodes().GetEndOfContent());
5229 SwTextFormatColl* pColl =
5230 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD,
5231 false);
5232 SwStartNode *pNode =
5233 m_rDoc.GetNodes().MakeTextSection(aIdx,
5234 SwNormalStartNode,pColl);
5235 m_pPaM->GetPoint()->nNode = pNode->GetIndex()+1;
5236 m_pPaM->GetPoint()->nContent.Assign(m_pPaM->GetContentNode(),0);
5237 aPlc.Get( nStart, nEnd, pDummy );
5238 ReadText(nStart,nEnd-nStart-1,MAN_MAINTEXT);
5241 else // ordinary case
5243 if (m_bNewDoc && m_pStg && !pGloss) /*meaningless for a glossary */
5245 m_pDocShell->SetIsTemplate( m_pWwFib->m_fDot ); // point at tgc record
5246 uno::Reference<document::XDocumentPropertiesSupplier> const
5247 xDocPropSupp(m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
5248 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
5250 OUString sCreatedFrom = xDocProps->getTemplateURL();
5251 uno::Reference< container::XNameContainer > xPrjNameCache;
5252 uno::Reference< lang::XMultiServiceFactory> xSF(m_pDocShell->GetModel(), uno::UNO_QUERY);
5253 if ( xSF.is() )
5254 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
5256 // Read Global templates
5257 ReadGlobalTemplateSettings( sCreatedFrom, xPrjNameCache );
5259 // Create and insert Word vba Globals
5260 uno::Any aGlobs;
5261 uno::Sequence< uno::Any > aArgs(1);
5262 aArgs[ 0 ] <<= m_pDocShell->GetModel();
5265 aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs );
5267 catch (const uno::Exception&)
5269 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available");
5272 #if HAVE_FEATURE_SCRIPTING
5273 if (!utl::ConfigManager::IsAvoidConfig())
5275 BasicManager *pBasicMan = m_pDocShell->GetBasicManager();
5276 if (pBasicMan)
5277 pBasicMan->SetGlobalUNOConstant( "VBAGlobals", aGlobs );
5279 #endif
5280 BasicProjImportHelper aBasicImporter( *m_pDocShell );
5281 // Import vba via oox filter
5282 bool bRet = aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
5284 lcl_createTemplateToProjectEntry( xPrjNameCache, sCreatedFrom, aBasicImporter.getProjectName() );
5285 WW8Customizations aCustomisations( m_pTableStream, *m_pWwFib );
5286 aCustomisations.Import( m_pDocShell );
5288 if( bRet )
5289 m_rDoc.SetContainsMSVBasic(true);
5291 StoreMacroCmds();
5293 m_bOnLoadingMain = true;
5294 ReadText(0, m_pWwFib->m_ccpText, MAN_MAINTEXT);
5295 m_bOnLoadingMain = false;
5298 ::SetProgressState(m_nProgress, m_pDocShell); // Update
5300 if (m_pDrawPg && m_pMSDffManager && m_pMSDffManager->GetShapeOrders())
5302 // Helper array to chain the inserted frames (instead of SdrTextObj)
5303 SvxMSDffShapeTxBxSort aTxBxSort;
5305 // Ensure correct z-order of read Escher objects
5306 sal_uInt16 nShapeCount = m_pMSDffManager->GetShapeOrders()->size();
5308 for (sal_uInt16 nShapeNum=0; nShapeNum < nShapeCount; nShapeNum++)
5310 SvxMSDffShapeOrder *pOrder =
5311 (*m_pMSDffManager->GetShapeOrders())[nShapeNum].get();
5312 // Insert Pointer into new Sort array
5313 if (pOrder->nTxBxComp && pOrder->pFly)
5314 aTxBxSort.insert(pOrder);
5316 // Chain Frames
5317 if( !aTxBxSort.empty() )
5319 SwFormatChain aChain;
5320 for( SvxMSDffShapeTxBxSort::iterator it = aTxBxSort.begin(); it != aTxBxSort.end(); ++it )
5322 SvxMSDffShapeOrder *pOrder = *it;
5324 // Initialize FlyFrame Formats
5325 SwFlyFrameFormat* pFlyFormat = pOrder->pFly;
5326 SwFlyFrameFormat* pNextFlyFormat = nullptr;
5327 SwFlyFrameFormat* pPrevFlyFormat = nullptr;
5329 // Determine successor, if we can
5330 SvxMSDffShapeTxBxSort::iterator tmpIter1 = it;
5331 ++tmpIter1;
5332 if( tmpIter1 != aTxBxSort.end() )
5334 SvxMSDffShapeOrder *pNextOrder = *tmpIter1;
5335 if ((0xFFFF0000 & pOrder->nTxBxComp)
5336 == (0xFFFF0000 & pNextOrder->nTxBxComp))
5337 pNextFlyFormat = pNextOrder->pFly;
5339 // Determine precessor, if we can
5340 if( it != aTxBxSort.begin() )
5342 SvxMSDffShapeTxBxSort::iterator tmpIter2 = it;
5343 --tmpIter2;
5344 SvxMSDffShapeOrder *pPrevOrder = *tmpIter2;
5345 if ((0xFFFF0000 & pOrder->nTxBxComp)
5346 == (0xFFFF0000 & pPrevOrder->nTxBxComp))
5347 pPrevFlyFormat = pPrevOrder->pFly;
5349 // If successor or predecessor present, insert the
5350 // chain at the FlyFrame Format
5351 if (pNextFlyFormat || pPrevFlyFormat)
5353 aChain.SetNext( pNextFlyFormat );
5354 aChain.SetPrev( pPrevFlyFormat );
5355 pFlyFormat->SetFormatAttr( aChain );
5361 if (m_bNewDoc)
5363 if( m_pWDop->fRevMarking )
5364 eMode |= RedlineFlags::On;
5365 if( m_pWDop->fRMView )
5366 eMode |= RedlineFlags::ShowDelete;
5369 m_aInsertedTables.DelAndMakeTableFrames();
5370 m_aSectionManager.InsertSegments();
5372 m_vColl.clear();
5374 DELETEZ( m_pStyles );
5376 if( m_pFormImpl )
5377 DeleteFormImpl();
5378 GrafikDtor();
5379 DELETEZ( m_pMSDffManager );
5380 DELETEZ( m_pHdFt );
5381 DELETEZ( m_pSBase );
5382 delete m_pWDop;
5383 DELETEZ( m_pFonts );
5384 delete m_pAtnNames;
5385 delete m_pSprmParser;
5386 ::EndProgress(m_pDocShell);
5388 m_pDataStream = nullptr;
5389 m_pTableStream = nullptr;
5391 DeleteCtrlStack();
5392 m_pRedlineStack->closeall(*m_pPaM->GetPoint());
5393 delete m_pRedlineStack;
5394 DeleteAnchorStack();
5395 DeleteRefStacks();
5397 // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5399 std::vector<const SwGrfNode*> vecBulletGrf;
5400 std::vector<SwFrameFormat*> vecFrameFormat;
5402 IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
5403 if ( pMarkAccess )
5405 IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findBookmark( "_PictureBullets" );
5406 if ( ppBkmk != pMarkAccess->getBookmarksEnd() &&
5407 IDocumentMarkAccess::GetType( *(ppBkmk->get()) ) == IDocumentMarkAccess::MarkType::BOOKMARK )
5409 SwTextNode* pTextNode = ppBkmk->get()->GetMarkStart().nNode.GetNode().GetTextNode();
5411 if ( pTextNode )
5413 const SwpHints* pHints = pTextNode->GetpSwpHints();
5414 for( size_t nHintPos = 0; pHints && nHintPos < pHints->Count(); ++nHintPos)
5416 const SwTextAttr *pHt = pHints->Get(nHintPos);
5417 const sal_Int32 st = pHt->GetStart();
5418 if( pHt
5419 && pHt->Which() == RES_TXTATR_FLYCNT
5420 && (st >= ppBkmk->get()->GetMarkStart().nContent.GetIndex()) )
5422 SwFrameFormat* pFrameFormat = pHt->GetFlyCnt().GetFrameFormat();
5423 vecFrameFormat.push_back(pFrameFormat);
5424 const SwNodeIndex* pNdIdx = pFrameFormat->GetContent().GetContentIdx();
5425 const SwNodes* pNodesArray = (pNdIdx != nullptr)
5426 ? &(pNdIdx->GetNodes())
5427 : nullptr;
5428 const SwGrfNode *pGrf = (pNodesArray != nullptr)
5429 ? dynamic_cast<const SwGrfNode*>((*pNodesArray)[pNdIdx->GetIndex() + 1])
5430 : nullptr;
5431 vecBulletGrf.push_back(pGrf);
5434 // update graphic bullet information
5435 size_t nCount = m_pLstManager->GetWW8LSTInfoNum();
5436 for (size_t i = 0; i < nCount; ++i)
5438 SwNumRule* pRule = m_pLstManager->GetNumRule(i);
5439 for (sal_uInt16 j = 0; j < MAXLEVEL; ++j)
5441 SwNumFormat aNumFormat(pRule->Get(j));
5442 const sal_Int16 nType = aNumFormat.GetNumberingType();
5443 const sal_uInt16 nGrfBulletCP = aNumFormat.GetGrfBulletCP();
5444 if ( nType == SVX_NUM_BITMAP
5445 && vecBulletGrf.size() > nGrfBulletCP
5446 && vecBulletGrf[nGrfBulletCP] != nullptr )
5448 Graphic aGraphic = vecBulletGrf[nGrfBulletCP]->GetGrf();
5449 SvxBrushItem aBrush(aGraphic, GPOS_AREA, SID_ATTR_BRUSH);
5450 const vcl::Font& aFont = numfunc::GetDefBulletFont();
5451 int nHeight = aFont.GetFontHeight() * 12;
5452 Size aPrefSize( aGraphic.GetPrefSize());
5453 if (aPrefSize.Height() * aPrefSize.Width() != 0 )
5455 int nWidth = (nHeight * aPrefSize.Width()) / aPrefSize.Height();
5456 Size aSize(nWidth, nHeight);
5457 aNumFormat.SetGraphicBrush(&aBrush, &aSize);
5459 else
5461 aNumFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
5462 aNumFormat.SetBulletChar(0x2190);
5464 pRule->Set( j, aNumFormat );
5468 // Remove additional pictures
5469 for (SwFrameFormat* p : vecFrameFormat)
5471 m_rDoc.getIDocumentLayoutAccess().DelLayoutFormat(p);
5476 DELETEZ( m_pLstManager );
5479 SAL_WARN_IF(m_pTableEndPaM, "sw.ww8", "document ended without table ending");
5480 m_pTableEndPaM.reset(); //ensure this is deleted before pPaM
5481 m_pPosAfterTOC.reset();
5482 mpCursor.reset();
5483 m_pPaM = nullptr;
5484 m_pLastAnchorPos.reset();//ensure this is deleted before UpdatePageDescs
5486 // remove extra paragraphs after attribute ctrl
5487 // stacks etc. are destroyed, and before fields
5488 // are updated
5489 m_aExtraneousParas.delete_all_from_doc();
5491 UpdateFields();
5493 DELETEZ(m_pWFlyPara);
5494 DELETEZ(m_pSFlyPara);
5496 // delete the pam before the call for hide all redlines (Bug 73683)
5497 if (m_bNewDoc)
5498 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(eMode);
5500 UpdatePageDescs(m_rDoc, nPageDescOffset);
5502 return nErrRet;
5505 sal_uLong SwWW8ImplReader::SetSubStreams(tools::SvRef<SotStorageStream> &rTableStream,
5506 tools::SvRef<SotStorageStream> &rDataStream)
5508 sal_uLong nErrRet = 0;
5509 // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5510 switch (m_pWwFib->m_nVersion)
5512 case 6:
5513 case 7:
5514 m_pTableStream = m_pStrm;
5515 m_pDataStream = m_pStrm;
5516 break;
5517 case 8:
5518 if(!m_pStg)
5520 OSL_ENSURE( m_pStg, "Version 8 always needs to have a Storage!!" );
5521 nErrRet = ERR_SWG_READ_ERROR;
5522 break;
5525 rTableStream = m_pStg->OpenSotStream( OUString::createFromAscii(
5526 m_pWwFib->m_fWhichTableStm ? SL::a1Table : SL::a0Table),
5527 StreamMode::STD_READ);
5529 m_pTableStream = rTableStream.get();
5530 m_pTableStream->SetEndian( SvStreamEndian::LITTLE );
5532 rDataStream = m_pStg->OpenSotStream(OUString(SL::aData),
5533 StreamMode::STD_READ );
5535 if (rDataStream.Is() && SVSTREAM_OK == rDataStream->GetError())
5537 m_pDataStream = rDataStream.get();
5538 m_pDataStream->SetEndian(SvStreamEndian::LITTLE);
5540 else
5541 m_pDataStream = m_pStrm;
5542 break;
5543 default:
5544 // Program error!
5545 OSL_ENSURE( false, "We forgot to encode nVersion!" );
5546 nErrRet = ERR_SWG_READ_ERROR;
5547 break;
5549 return nErrRet;
5552 namespace
5554 utl::TempFile *MakeTemp(SvFileStream &rSt)
5556 utl::TempFile *pT = new utl::TempFile;
5557 pT->EnableKillingFile();
5558 rSt.Open(pT->GetFileName(), StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
5559 return pT;
5562 #define WW_BLOCKSIZE 0x200
5564 void DecryptRC4(msfilter::MSCodec97& rCtx, SvStream &rIn, SvStream &rOut)
5566 rIn.Seek(STREAM_SEEK_TO_END);
5567 const std::size_t nLen = rIn.Tell();
5568 rIn.Seek(0);
5570 sal_uInt8 in[WW_BLOCKSIZE];
5571 for (std::size_t nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
5573 std::size_t nBS = (nLen - nI > WW_BLOCKSIZE) ? WW_BLOCKSIZE : nLen - nI;
5574 nBS = rIn.ReadBytes(in, nBS);
5575 rCtx.InitCipher(nBlock);
5576 rCtx.Decode(in, nBS, in, nBS);
5577 rOut.WriteBytes(in, nBS);
5581 void DecryptXOR(msfilter::MSCodec_XorWord95 &rCtx, SvStream &rIn, SvStream &rOut)
5583 std::size_t nSt = rIn.Tell();
5584 rIn.Seek(STREAM_SEEK_TO_END);
5585 std::size_t nLen = rIn.Tell();
5586 rIn.Seek(nSt);
5588 rCtx.InitCipher();
5589 rCtx.Skip(nSt);
5591 sal_uInt8 in[0x4096];
5592 for (std::size_t nI = nSt; nI < nLen; nI += 0x4096)
5594 std::size_t nBS = (nLen - nI > 0x4096 ) ? 0x4096 : nLen - nI;
5595 nBS = rIn.ReadBytes(in, nBS);
5596 rCtx.Decode(in, nBS);
5597 rOut.WriteBytes(in, nBS);
5601 // moan, copy and paste :-(
5602 OUString QueryPasswordForMedium(SfxMedium& rMedium)
5604 OUString aPassw;
5606 using namespace com::sun::star;
5608 const SfxItemSet* pSet = rMedium.GetItemSet();
5609 const SfxPoolItem *pPasswordItem;
5611 if(pSet && SfxItemState::SET == pSet->GetItemState(SID_PASSWORD, true, &pPasswordItem))
5612 aPassw = static_cast<const SfxStringItem *>(pPasswordItem)->GetValue();
5613 else
5617 uno::Reference< task::XInteractionHandler > xHandler( rMedium.GetInteractionHandler() );
5618 if( xHandler.is() )
5620 ::comphelper::DocPasswordRequest* pRequest = new ::comphelper::DocPasswordRequest(
5621 ::comphelper::DocPasswordRequestType::MS, task::PasswordRequestMode_PASSWORD_ENTER,
5622 INetURLObject( rMedium.GetOrigURL() ).GetName( INetURLObject::DecodeMechanism::WithCharset ) );
5623 uno::Reference< task::XInteractionRequest > xRequest( pRequest );
5625 xHandler->handle( xRequest );
5627 if( pRequest->isPassword() )
5628 aPassw = pRequest->getPassword();
5631 catch( const uno::Exception& )
5636 return aPassw;
5639 uno::Sequence< beans::NamedValue > InitXorWord95Codec( ::msfilter::MSCodec_XorWord95& rCodec, SfxMedium& rMedium, WW8Fib* pWwFib )
5641 uno::Sequence< beans::NamedValue > aEncryptionData;
5642 const SfxUnoAnyItem* pEncryptionData = SfxItemSet::GetItem<SfxUnoAnyItem>(rMedium.GetItemSet(), SID_ENCRYPTIONDATA, false);
5643 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5644 aEncryptionData.realloc( 0 );
5646 if ( !aEncryptionData.getLength() )
5648 OUString sUniPassword = QueryPasswordForMedium( rMedium );
5650 OString sPassword(OUStringToOString(sUniPassword,
5651 WW8Fib::GetFIBCharset(pWwFib->m_chseTables, pWwFib->m_lid)));
5653 sal_Int32 nLen = sPassword.getLength();
5654 if( nLen <= 15 )
5656 sal_uInt8 pPassword[16];
5657 memcpy(pPassword, sPassword.getStr(), nLen);
5658 memset(pPassword+nLen, 0, sizeof(pPassword)-nLen);
5660 rCodec.InitKey( pPassword );
5661 aEncryptionData = rCodec.GetEncryptionData();
5663 // the export supports RC4 algorithm only, so we have to
5664 // generate the related EncryptionData as well, so that Save
5665 // can export the document without asking for a password;
5666 // as result there will be EncryptionData for both algorithms
5667 // in the MediaDescriptor
5668 ::msfilter::MSCodec_Std97 aCodec97;
5670 // Generate random number with a seed of time as salt.
5671 TimeValue aTime;
5672 osl_getSystemTime( &aTime );
5673 rtlRandomPool aRandomPool = rtl_random_createPool();
5674 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
5676 sal_uInt8 pDocId[ 16 ];
5677 rtl_random_getBytes( aRandomPool, pDocId, 16 );
5679 rtl_random_destroyPool( aRandomPool );
5681 sal_uInt16 pStd97Pass[16];
5682 memset( pStd97Pass, 0, sizeof( pStd97Pass ) );
5683 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5684 pStd97Pass[nChar] = sUniPassword[nChar];
5686 aCodec97.InitKey( pStd97Pass, pDocId );
5688 // merge the EncryptionData, there should be no conflicts
5689 ::comphelper::SequenceAsHashMap aEncryptionHash( aEncryptionData );
5690 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
5691 aEncryptionHash >> aEncryptionData;
5695 return aEncryptionData;
5698 uno::Sequence< beans::NamedValue > Init97Codec(msfilter::MSCodec97& rCodec, sal_uInt8 pDocId[16], SfxMedium& rMedium)
5700 uno::Sequence< beans::NamedValue > aEncryptionData;
5701 const SfxUnoAnyItem* pEncryptionData = SfxItemSet::GetItem<SfxUnoAnyItem>(rMedium.GetItemSet(), SID_ENCRYPTIONDATA, false);
5702 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5703 aEncryptionData.realloc( 0 );
5705 if ( !aEncryptionData.getLength() )
5707 OUString sUniPassword = QueryPasswordForMedium( rMedium );
5709 sal_Int32 nLen = sUniPassword.getLength();
5710 if ( nLen <= 15 )
5712 sal_uInt16 pPassword[16];
5713 memset( pPassword, 0, sizeof( pPassword ) );
5714 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5715 pPassword[nChar] = sUniPassword[nChar];
5717 rCodec.InitKey( pPassword, pDocId );
5718 aEncryptionData = rCodec.GetEncryptionData();
5722 return aEncryptionData;
5726 //TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5727 //stream thing
5728 static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo &info, SvStream &rStream)
5730 //Its possible there are other variants in existance but these
5731 //are the defaults I get with Word 2013
5733 rStream.ReadUInt32(info.header.flags);
5734 if (oox::getFlag( info.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
5735 return false;
5737 sal_uInt32 nHeaderSize(0);
5738 rStream.ReadUInt32(nHeaderSize);
5739 sal_uInt32 actualHeaderSize = sizeof(info.header);
5741 if (nHeaderSize < actualHeaderSize)
5742 return false;
5744 rStream.ReadUInt32(info.header.flags);
5745 rStream.ReadUInt32(info.header.sizeExtra);
5746 rStream.ReadUInt32(info.header.algId);
5747 rStream.ReadUInt32(info.header.algIdHash);
5748 rStream.ReadUInt32(info.header.keyBits);
5749 rStream.ReadUInt32(info.header.providedType);
5750 rStream.ReadUInt32(info.header.reserved1);
5751 rStream.ReadUInt32(info.header.reserved2);
5753 rStream.SeekRel(nHeaderSize - actualHeaderSize);
5755 rStream.ReadUInt32(info.verifier.saltSize);
5756 if (info.verifier.saltSize != msfilter::SALT_LENGTH)
5757 return false;
5758 rStream.ReadBytes(&info.verifier.salt, sizeof(info.verifier.salt));
5759 rStream.ReadBytes(&info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier));
5761 rStream.ReadUInt32(info.verifier.encryptedVerifierHashSize);
5762 if (info.verifier.encryptedVerifierHashSize != RTL_DIGEST_LENGTH_SHA1)
5763 return false;
5764 rStream.ReadBytes(&info.verifier.encryptedVerifierHash, info.verifier.encryptedVerifierHashSize);
5766 // check flags and algorithm IDs, required are AES128 and SHA-1
5767 if (!oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
5768 return false;
5770 if (oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_AES))
5771 return false;
5773 if (info.header.algId != msfilter::ENCRYPT_ALGO_RC4)
5774 return false;
5776 // hash algorithm ID 0 defaults to SHA-1 too
5777 if (info.header.algIdHash != 0 && info.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
5778 return false;
5780 return true;
5783 sal_uLong SwWW8ImplReader::LoadThroughDecryption(WW8Glossary *pGloss)
5785 sal_uLong nErrRet = 0;
5786 if (pGloss)
5787 m_pWwFib = pGloss->GetFib();
5788 else
5789 m_pWwFib = new WW8Fib(*m_pStrm, m_nWantedVersion);
5791 if (m_pWwFib->m_nFibError)
5792 nErrRet = ERR_SWG_READ_ERROR;
5794 tools::SvRef<SotStorageStream> xTableStream, xDataStream;
5796 if (!nErrRet)
5797 nErrRet = SetSubStreams(xTableStream, xDataStream);
5799 utl::TempFile *pTempMain = nullptr;
5800 utl::TempFile *pTempTable = nullptr;
5801 utl::TempFile *pTempData = nullptr;
5802 SvFileStream aDecryptMain;
5803 SvFileStream aDecryptTable;
5804 SvFileStream aDecryptData;
5806 bool bDecrypt = false;
5807 enum {RC4CryptoAPI, RC4, XOR, Other} eAlgo = Other;
5808 if (m_pWwFib->m_fEncrypted && !nErrRet)
5810 if (!pGloss)
5812 bDecrypt = true;
5813 if (8 != m_pWwFib->m_nVersion)
5814 eAlgo = XOR;
5815 else
5817 if (m_pWwFib->m_nKey != 0)
5818 eAlgo = XOR;
5819 else
5821 m_pTableStream->Seek(0);
5822 sal_uInt32 nEncType(0);
5823 m_pTableStream->ReadUInt32(nEncType);
5824 if (nEncType == msfilter::VERSION_INFO_1997_FORMAT)
5825 eAlgo = RC4;
5826 else if (nEncType == msfilter::VERSION_INFO_2007_FORMAT || nEncType == msfilter::VERSION_INFO_2007_FORMAT_SP2)
5827 eAlgo = RC4CryptoAPI;
5833 if (bDecrypt)
5835 nErrRet = ERRCODE_SVX_WRONGPASS;
5836 SfxMedium* pMedium = m_pDocShell->GetMedium();
5838 if ( pMedium )
5840 switch (eAlgo)
5842 default:
5843 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5844 break;
5845 case XOR:
5847 msfilter::MSCodec_XorWord95 aCtx;
5848 uno::Sequence< beans::NamedValue > aEncryptionData = InitXorWord95Codec( aCtx, *pMedium, m_pWwFib );
5850 // if initialization has failed the EncryptionData should be empty
5851 if ( aEncryptionData.getLength() && aCtx.VerifyKey( m_pWwFib->m_nKey, m_pWwFib->m_nHash ) )
5853 nErrRet = 0;
5854 pTempMain = MakeTemp(aDecryptMain);
5856 m_pStrm->Seek(0);
5857 size_t nUnencryptedHdr =
5858 (8 == m_pWwFib->m_nVersion) ? 0x44 : 0x34;
5859 sal_uInt8 *pIn = new sal_uInt8[nUnencryptedHdr];
5860 nUnencryptedHdr = m_pStrm->ReadBytes(pIn, nUnencryptedHdr);
5861 aDecryptMain.WriteBytes(pIn, nUnencryptedHdr);
5862 delete [] pIn;
5864 DecryptXOR(aCtx, *m_pStrm, aDecryptMain);
5866 if (!m_pTableStream || m_pTableStream == m_pStrm)
5867 m_pTableStream = &aDecryptMain;
5868 else
5870 pTempTable = MakeTemp(aDecryptTable);
5871 DecryptXOR(aCtx, *m_pTableStream, aDecryptTable);
5872 m_pTableStream = &aDecryptTable;
5875 if (!m_pDataStream || m_pDataStream == m_pStrm)
5876 m_pDataStream = &aDecryptMain;
5877 else
5879 pTempData = MakeTemp(aDecryptData);
5880 DecryptXOR(aCtx, *m_pDataStream, aDecryptData);
5881 m_pDataStream = &aDecryptData;
5884 pMedium->GetItemSet()->ClearItem( SID_PASSWORD );
5885 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
5888 break;
5889 case RC4:
5890 case RC4CryptoAPI:
5892 std::unique_ptr<msfilter::MSCodec97> xCtx;
5893 msfilter::RC4EncryptionInfo info;
5894 bool bCouldReadHeaders;
5896 if (eAlgo == RC4)
5898 xCtx.reset(new msfilter::MSCodec_Std97);
5899 assert(sizeof(info.verifier.encryptedVerifierHash) >= RTL_DIGEST_LENGTH_MD5);
5900 bCouldReadHeaders =
5901 checkRead(*m_pTableStream, info.verifier.salt, sizeof(info.verifier.salt)) &&
5902 checkRead(*m_pTableStream, info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier)) &&
5903 checkRead(*m_pTableStream, info.verifier.encryptedVerifierHash, RTL_DIGEST_LENGTH_MD5);
5905 else
5907 xCtx.reset(new msfilter::MSCodec_CryptoAPI);
5908 bCouldReadHeaders = lclReadCryptoAPIHeader(info, *m_pTableStream);
5911 // if initialization has failed the EncryptionData should be empty
5912 uno::Sequence< beans::NamedValue > aEncryptionData;
5913 if (bCouldReadHeaders)
5914 aEncryptionData = Init97Codec(*xCtx, info.verifier.salt, *pMedium);
5915 else
5916 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5917 if (aEncryptionData.getLength() && xCtx->VerifyKey(info.verifier.encryptedVerifier,
5918 info.verifier.encryptedVerifierHash))
5920 nErrRet = 0;
5922 pTempMain = MakeTemp(aDecryptMain);
5924 m_pStrm->Seek(0);
5925 std::size_t nUnencryptedHdr = 0x44;
5926 sal_uInt8 *pIn = new sal_uInt8[nUnencryptedHdr];
5927 nUnencryptedHdr = m_pStrm->ReadBytes(pIn, nUnencryptedHdr);
5929 DecryptRC4(*xCtx, *m_pStrm, aDecryptMain);
5931 aDecryptMain.Seek(0);
5932 aDecryptMain.WriteBytes(pIn, nUnencryptedHdr);
5933 delete [] pIn;
5935 pTempTable = MakeTemp(aDecryptTable);
5936 DecryptRC4(*xCtx, *m_pTableStream, aDecryptTable);
5937 m_pTableStream = &aDecryptTable;
5939 if (!m_pDataStream || m_pDataStream == m_pStrm)
5940 m_pDataStream = &aDecryptMain;
5941 else
5943 pTempData = MakeTemp(aDecryptData);
5944 DecryptRC4(*xCtx, *m_pDataStream, aDecryptData);
5945 m_pDataStream = &aDecryptData;
5948 pMedium->GetItemSet()->ClearItem( SID_PASSWORD );
5949 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
5952 break;
5956 if (nErrRet == 0)
5958 m_pStrm = &aDecryptMain;
5960 delete m_pWwFib;
5961 m_pWwFib = new WW8Fib(*m_pStrm, m_nWantedVersion);
5962 if (m_pWwFib->m_nFibError)
5963 nErrRet = ERR_SWG_READ_ERROR;
5967 if (!nErrRet)
5968 nErrRet = CoreLoad(pGloss);
5970 delete pTempMain;
5971 delete pTempTable;
5972 delete pTempData;
5974 if (!pGloss)
5975 delete m_pWwFib;
5976 return nErrRet;
5979 void SwWW8ImplReader::SetOutlineStyles()
5981 // If we are inserted into a document then don't clobber existing outline
5982 // levels.
5983 sal_uInt16 nOutlineStyleListLevelWithAssignment = 0;
5984 if (!m_bNewDoc)
5986 ww8::ParaStyles aOutLined(sw::util::GetParaStyles(m_rDoc));
5987 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined);
5988 ww8::ParaStyles::reverse_iterator aEnd = aOutLined.rend();
5989 for ( ww8::ParaStyles::reverse_iterator aIter = aOutLined.rbegin(); aIter < aEnd; ++aIter)
5991 if ((*aIter)->IsAssignedToListLevelOfOutlineStyle())
5992 nOutlineStyleListLevelWithAssignment |= 1 << (*aIter)->GetAssignedOutlineStyleLevel();
5993 else
5994 break;
5998 // Check applied WW8 list styles at WW8 Built-In Heading Styles
5999 // - Choose the list style which occurs most often as the one which provides
6000 // the list level properties for the Outline Style.
6001 // - Populate temporary list of WW8 Built-In Heading Styles for further
6002 // iteration
6003 std::vector<SwWW8StyInf*> aWW8BuiltInHeadingStyles;
6004 const SwNumRule* pChosenWW8ListStyle = nullptr;
6006 std::map<const SwNumRule*, int> aWW8ListStyleCounts;
6007 for (SwWW8StyInf & rSI : m_vColl)
6009 if (!rSI.IsWW8BuiltInHeadingStyle() || !rSI.HasWW8OutlineLevel())
6011 continue;
6014 aWW8BuiltInHeadingStyles.push_back(&rSI);
6016 const SwNumRule* pWW8ListStyle = rSI.GetOutlineNumrule();
6017 if (pWW8ListStyle != nullptr)
6019 std::map<const SwNumRule*, int>::iterator aCountIter
6020 = aWW8ListStyleCounts.find(pWW8ListStyle);
6021 if (aCountIter == aWW8ListStyleCounts.end())
6023 aWW8ListStyleCounts[pWW8ListStyle] = 1;
6025 else
6027 ++(aCountIter->second);
6032 int nCurrentMaxCount = 0;
6033 std::map<const SwNumRule*, int>::iterator aCountIterEnd
6034 = aWW8ListStyleCounts.end();
6035 for (std::map<const SwNumRule*, int>::iterator aIter
6036 = aWW8ListStyleCounts.begin();
6037 aIter != aCountIterEnd; ++aIter)
6039 if (aIter->second > nCurrentMaxCount)
6041 nCurrentMaxCount = aIter->second;
6042 pChosenWW8ListStyle = aIter->first;
6047 // - set list level properties of Outline Style - ODF's list style applied
6048 // by default to headings
6049 // - assign corresponding Heading Paragraph Styles to the Outline Style
6050 // - If a heading Paragraph Styles is not applying the WW8 list style which
6051 // had been chosen as
6052 // the one which provides the list level properties for the Outline Style,
6053 // its assignment to
6054 // the Outline Style is removed. A potential applied WW8 list style is
6055 // assigned directly and
6056 // its default outline level is applied.
6057 SwNumRule aOutlineRule(*m_rDoc.GetOutlineNumRule());
6058 bool bAppliedChangedOutlineStyle = false;
6059 std::vector<SwWW8StyInf*>::iterator aStylesIterEnd
6060 = aWW8BuiltInHeadingStyles.end();
6061 for (std::vector<SwWW8StyInf*>::iterator aStyleIter
6062 = aWW8BuiltInHeadingStyles.begin();
6063 aStyleIter != aStylesIterEnd; ++aStyleIter)
6065 SwWW8StyInf* pStyleInf = (*aStyleIter);
6067 if (!pStyleInf->m_bColl) //Character Style
6068 continue;
6070 const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6071 = 1 << pStyleInf->mnWW8OutlineLevel;
6072 if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6073 & nOutlineStyleListLevelWithAssignment)
6075 continue;
6078 if (pChosenWW8ListStyle != nullptr && pStyleInf->mnWW8OutlineLevel
6079 == pStyleInf->m_nListLevel)
6081 const SwNumFormat& rRule
6082 = pChosenWW8ListStyle->Get(pStyleInf->mnWW8OutlineLevel);
6083 aOutlineRule.Set(pStyleInf->mnWW8OutlineLevel, rRule);
6084 bAppliedChangedOutlineStyle = true;
6087 // in case that there are more styles on this level ignore them
6088 nOutlineStyleListLevelWithAssignment
6089 |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle;
6091 SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pStyleInf->m_pFormat);
6092 if (pStyleInf->GetOutlineNumrule() != pChosenWW8ListStyle
6093 || (pStyleInf->m_nListLevel < WW8ListManager::nMaxLevel
6094 && pStyleInf->mnWW8OutlineLevel != pStyleInf->m_nListLevel))
6096 // WW8 Built-In Heading Style does not apply the chosen one.
6097 // --> delete assignment to OutlineStyle, but keep its current
6098 // outline level
6099 pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
6100 // Apply existing WW8 list style a normal list style at the
6101 // Paragraph Style
6102 if (pStyleInf->GetOutlineNumrule() != nullptr)
6104 pTextFormatColl->SetFormatAttr(
6105 SwNumRuleItem(pStyleInf->GetOutlineNumrule()->GetName()));
6107 // apply default outline level of WW8 Built-in Heading Style
6108 const sal_uInt8 nOutlineLevel
6109 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6110 pStyleInf->mnWW8OutlineLevel);
6111 pTextFormatColl->SetFormatAttr(
6112 SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
6114 else
6116 pTextFormatColl->AssignToListLevelOfOutlineStyle(
6117 pStyleInf->mnWW8OutlineLevel);
6121 if (bAppliedChangedOutlineStyle)
6123 m_rDoc.SetOutlineNumRule(aOutlineRule);
6127 const OUString* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx)
6129 if (!m_pAtnNames && m_pWwFib->m_lcbGrpStAtnOwners)
6131 // Determine authors: can be found in the TableStream
6132 m_pAtnNames = new std::vector<OUString>;
6133 SvStream& rStrm = *m_pTableStream;
6135 long nOldPos = rStrm.Tell();
6136 rStrm.Seek( m_pWwFib->m_fcGrpStAtnOwners );
6138 long nRead = 0, nCount = m_pWwFib->m_lcbGrpStAtnOwners;
6139 while (nRead < nCount)
6141 if( m_bVer67 )
6143 m_pAtnNames->push_back(read_uInt8_PascalString(rStrm,
6144 RTL_TEXTENCODING_MS_1252));
6145 nRead += m_pAtnNames->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6147 else
6149 m_pAtnNames->push_back(read_uInt16_PascalString(rStrm));
6150 // Unicode: double the length + sal_uInt16 count
6151 nRead += (m_pAtnNames->rbegin()->getLength() + 1)*2;
6154 rStrm.Seek( nOldPos );
6157 const OUString *pRet = nullptr;
6158 if (m_pAtnNames && nIdx < m_pAtnNames->size())
6159 pRet = &((*m_pAtnNames)[nIdx]);
6160 return pRet;
6163 void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark& rMark)
6165 if (!m_pSmartTagData && m_pWwFib->m_lcbFactoidData)
6167 m_pSmartTagData.reset(new WW8SmartTagData());
6168 m_pSmartTagData->Read(*m_pTableStream, m_pWwFib->m_fcFactoidData, m_pWwFib->m_lcbFactoidData);
6171 // Check if the handle is a valid smart tag bookmark index.
6172 size_t nIndex = rMark.GetHandle();
6173 if (nIndex >= m_pSmartTagData->m_aPropBags.size())
6174 return;
6176 // Check if the smart tag bookmark refers to a valid factoid type.
6177 const MSOPropertyBag& rPropertyBag = m_pSmartTagData->m_aPropBags[rMark.GetHandle()];
6178 auto itPropertyBag = m_pSmartTagData->m_aPropBagStore.m_aFactoidTypes.begin();
6179 for (; itPropertyBag != m_pSmartTagData->m_aPropBagStore.m_aFactoidTypes.end(); ++itPropertyBag)
6180 if (itPropertyBag->m_nId == rPropertyBag.m_nId)
6181 break;
6182 if (itPropertyBag == m_pSmartTagData->m_aPropBagStore.m_aFactoidTypes.end())
6183 return;
6185 // Check if the factoid is an RDF one.
6186 const MSOFactoidType& rFactoidType = *itPropertyBag;
6187 if (rFactoidType.m_aUri != "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6188 return;
6190 // Finally put the relevant attributes to the mark.
6191 std::vector< std::pair<OUString, OUString> > aAttributes;
6192 for (const MSOProperty& rProperty : rPropertyBag.m_aProperties)
6194 OUString aKey;
6195 OUString aValue;
6196 if (rProperty.m_nKey < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6197 aKey = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nKey];
6198 if (rProperty.m_nValue < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6199 aValue = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nValue];
6200 if (!aKey.isEmpty() && !aValue.isEmpty())
6201 aAttributes.push_back(std::make_pair(aKey, aValue));
6203 rMark.SetAttributes(aAttributes);
6206 sal_uLong SwWW8ImplReader::LoadDoc(WW8Glossary *pGloss)
6208 sal_uLong nErrRet = 0;
6211 static const sal_Char* aNames[ 13 ] = {
6212 "WinWord/WW", "WinWord/WW8", "WinWord/WWFT",
6213 "WinWord/WWFLX", "WinWord/WWFLY",
6214 "WinWord/WWF",
6215 "WinWord/WWFA0", "WinWord/WWFA1", "WinWord/WWFA2",
6216 "WinWord/WWFB0", "WinWord/WWFB1", "WinWord/WWFB2",
6217 "WinWord/RegardHindiDigits"
6219 sal_uInt64 aVal[ 13 ];
6221 SwFilterOptions aOpt( 13, aNames, aVal );
6223 m_nIniFlags = aVal[ 0 ];
6224 m_nIniFlags1= aVal[ 1 ];
6225 // Moves Flys by x twips to the right or left
6226 m_nIniFlyDx = aVal[ 3 ];
6227 m_nIniFlyDy = aVal[ 4 ];
6229 m_nFieldFlags = aVal[ 5 ];
6230 m_nFieldTagAlways[0] = aVal[ 6 ];
6231 m_nFieldTagAlways[1] = aVal[ 7 ];
6232 m_nFieldTagAlways[2] = aVal[ 8 ];
6233 m_nFieldTagBad[0] = aVal[ 9 ];
6234 m_nFieldTagBad[1] = aVal[ 10 ];
6235 m_nFieldTagBad[2] = aVal[ 11 ];
6236 m_bRegardHindiDigits = aVal[ 12 ] > 0;
6239 sal_uInt16 nMagic(0);
6240 m_pStrm->ReadUInt16( nMagic );
6242 // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6243 switch (m_nWantedVersion)
6245 case 6:
6246 case 7:
6247 if (
6248 0xa59b != nMagic && 0xa59c != nMagic &&
6249 0xa5dc != nMagic && 0xa5db != nMagic &&
6250 (nMagic < 0xa697 || nMagic > 0xa699)
6253 // Test for own 97 fake!
6254 if (m_pStg && 0xa5ec == nMagic)
6256 sal_uLong nCurPos = m_pStrm->Tell();
6257 if (m_pStrm->Seek(nCurPos + 22))
6259 sal_uInt32 nfcMin;
6260 m_pStrm->ReadUInt32( nfcMin );
6261 if (0x300 != nfcMin)
6262 nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
6264 m_pStrm->Seek( nCurPos );
6266 else
6267 nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
6269 break;
6270 case 8:
6271 if (0xa5ec != nMagic)
6272 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
6273 break;
6274 default:
6275 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
6276 OSL_ENSURE( false, "We forgot to encode nVersion!" );
6277 break;
6280 if (!nErrRet)
6281 nErrRet = LoadThroughDecryption(pGloss);
6283 m_rDoc.PropagateOutlineRule();
6285 return nErrRet;
6288 extern "C" SAL_DLLPUBLIC_EXPORT Reader* SAL_CALL ImportDOC()
6290 return new WW8Reader();
6293 extern "C" SAL_DLLPUBLIC_EXPORT bool SAL_CALL TestImportDOC(const OUString &rURL, const OUString &rFltName)
6295 Reader *pReader = ImportDOC();
6297 SvFileStream aFileStream(rURL, StreamMode::READ);
6298 tools::SvRef<SotStorage> xStorage;
6299 pReader->pStrm = &aFileStream;
6300 if (rFltName != "WW6")
6302 xStorage = tools::SvRef<SotStorage>(new SotStorage(aFileStream));
6303 pReader->pStg = xStorage.get();
6305 pReader->SetFltName(rFltName);
6307 SwGlobals::ensure();
6309 SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
6310 xDocSh->DoInitNew();
6311 SwDoc *pD = static_cast<SwDocShell*>((&xDocSh))->GetDoc();
6313 SwNodeIndex aIdx(
6314 *pD->GetNodes().GetEndOfContent().StartOfSectionNode(), 1);
6315 if( !aIdx.GetNode().IsTextNode() )
6317 pD->GetNodes().GoNext( &aIdx );
6319 SwPaM aPaM( aIdx );
6320 aPaM.GetPoint()->nContent.Assign(aIdx.GetNode().GetContentNode(), 0);
6321 bool bRet = pReader->Read(*pD, OUString(), aPaM, OUString()) == 0;
6322 delete pReader;
6323 return bRet;
6326 sal_uLong WW8Reader::OpenMainStream( tools::SvRef<SotStorageStream>& rRef, sal_uInt16& rBuffSize )
6328 sal_uLong nRet = ERR_SWG_READ_ERROR;
6329 OSL_ENSURE( pStg.get(), "Where is my Storage?" );
6330 rRef = pStg->OpenSotStream( "WordDocument", StreamMode::READ | StreamMode::SHARE_DENYALL);
6332 if( rRef.Is() )
6334 if( SVSTREAM_OK == rRef->GetError() )
6336 sal_uInt16 nOld = rRef->GetBufferSize();
6337 rRef->SetBufferSize( rBuffSize );
6338 rBuffSize = nOld;
6339 nRet = 0;
6341 else
6342 nRet = rRef->GetError();
6344 return nRet;
6347 sal_uLong WW8Reader::Read(SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, const OUString & /* FileName */)
6349 sal_uInt16 nOldBuffSize = 32768;
6350 bool bNew = !bInsertMode; // New Doc (no inserting)
6352 tools::SvRef<SotStorageStream> refStrm; // So that no one else can steal the Stream
6353 SvStream* pIn = pStrm;
6355 sal_uLong nRet = 0;
6356 sal_uInt8 nVersion = 8;
6358 const OUString sFltName = GetFltName();
6359 if ( sFltName=="WW6" )
6361 if (pStrm)
6362 nVersion = 6;
6363 else
6365 OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream");
6366 nRet = ERR_SWG_READ_ERROR;
6369 else
6371 if ( sFltName=="CWW6" )
6372 nVersion = 6;
6373 else if ( sFltName=="CWW7" )
6374 nVersion = 7;
6376 if( pStg.Is() )
6378 nRet = OpenMainStream( refStrm, nOldBuffSize );
6379 pIn = refStrm.get();
6381 else
6383 OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage");
6384 nRet = ERR_SWG_READ_ERROR;
6388 if( !nRet )
6390 std::unique_ptr<SwWW8ImplReader> pRdr(new SwWW8ImplReader(nVersion, pStg.get(), pIn, rDoc,
6391 rBaseURL, bNew, bSkipImages, *rPaM.GetPoint()));
6392 if (bNew)
6394 // Remove Frame and offsets from Frame Template
6395 Reader::ResetFrameFormats( rDoc );
6397 rPaM.GetBound().nContent.Assign(nullptr, 0);
6398 rPaM.GetBound(false).nContent.Assign(nullptr, 0);
6403 nRet = pRdr->LoadDoc();
6405 catch( const std::exception& )
6407 nRet = ERR_WW8_NO_WW8_FILE_ERR;
6410 if( refStrm.Is() )
6412 refStrm->SetBufferSize( nOldBuffSize );
6413 refStrm.Clear();
6415 else
6417 pIn->ResetError();
6421 return nRet;
6424 int WW8Reader::GetReaderType()
6426 return SW_STORAGE_READER | SW_STREAM_READER;
6429 bool WW8Reader::HasGlossaries() const
6431 return true;
6434 bool WW8Reader::ReadGlossaries(SwTextBlocks& rBlocks, bool bSaveRelFiles) const
6436 bool bRet=false;
6438 WW8Reader *pThis = const_cast<WW8Reader *>(this);
6440 sal_uInt16 nOldBuffSize = 32768;
6441 tools::SvRef<SotStorageStream> refStrm;
6442 if (!pThis->OpenMainStream(refStrm, nOldBuffSize))
6444 WW8Glossary aGloss( refStrm, 8, pStg.get() );
6445 bRet = aGloss.Load( rBlocks, bSaveRelFiles );
6447 return bRet;
6450 bool SwMSDffManager::GetOLEStorageName(long nOLEId, OUString& rStorageName,
6451 tools::SvRef<SotStorage>& rSrcStorage, uno::Reference < embed::XStorage >& rDestStorage) const
6453 bool bRet = false;
6455 sal_Int32 nPictureId = 0;
6456 if (rReader.m_pStg)
6458 // Via the TextBox-PLCF we get the right char Start-End positions
6459 // We should then find the EmbeddedField and the corresponding Sprms
6460 // in that Area.
6461 // We only need the Sprm for the Picture Id.
6462 long nOldPos = rReader.m_pStrm->Tell();
6464 // #i32596# - consider return value of method
6465 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6466 // wasn't successful. Thus, continue in this case.
6467 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6468 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6469 WW8_CP nStartCp, nEndCp;
6470 if ( rReader.m_bDrawCpOValid && rReader.GetTxbxTextSttEndCp(nStartCp, nEndCp,
6471 static_cast<sal_uInt16>((nOLEId >> 16) & 0xFFFF),
6472 static_cast<sal_uInt16>(nOLEId & 0xFFFF)) )
6474 WW8PLCFxSaveAll aSave;
6475 memset( &aSave, 0, sizeof( aSave ) );
6476 rReader.m_pPlcxMan->SaveAllPLCFx( aSave );
6478 nStartCp += rReader.m_nDrawCpO;
6479 nEndCp += rReader.m_nDrawCpO;
6480 WW8PLCFx_Cp_FKP* pChp = rReader.m_pPlcxMan->GetChpPLCF();
6481 wwSprmParser aSprmParser(*rReader.m_pWwFib);
6482 while (nStartCp <= nEndCp && !nPictureId)
6484 if (!pChp->SeekPos( nStartCp))
6485 break;
6486 WW8PLCFxDesc aDesc;
6487 pChp->GetSprms( &aDesc );
6489 if (aDesc.nSprmsLen && aDesc.pMemPos) // Attributes present
6491 long nLen = aDesc.nSprmsLen;
6492 const sal_uInt8* pSprm = aDesc.pMemPos;
6494 while (nLen >= 2 && !nPictureId)
6496 sal_uInt16 nId = aSprmParser.GetSprmId(pSprm);
6497 sal_uInt16 nSL = aSprmParser.GetSprmSize(nId, pSprm, nLen);
6499 if( nLen < nSL )
6500 break; // Not enough Bytes left
6502 if( 0x6A03 == nId && 0 < nLen )
6504 nPictureId = SVBT32ToUInt32(pSprm +
6505 aSprmParser.DistanceToData(nId));
6506 bRet = true;
6508 pSprm += nSL;
6509 nLen -= nSL;
6512 nStartCp = aDesc.nEndPos;
6515 rReader.m_pPlcxMan->RestoreAllPLCFx( aSave );
6518 rReader.m_pStrm->Seek( nOldPos );
6521 if( bRet )
6523 rStorageName = "_";
6524 rStorageName += OUString::number(nPictureId);
6525 rSrcStorage = rReader.m_pStg->OpenSotStorage(OUString(
6526 SL::aObjectPool));
6527 if (!rReader.m_pDocShell)
6528 bRet=false;
6529 else
6530 rDestStorage = rReader.m_pDocShell->GetStorage();
6532 return bRet;
6536 * When reading a single Box (which possibly is part of a group), we do
6537 * not yet have enough information to decide whether we need it as a TextField
6538 * or not.
6539 * So convert all of them as a precaution.
6540 * FIXME: Actually implement this!
6542 bool SwMSDffManager::ShapeHasText(sal_uLong, sal_uLong) const
6544 return true;
6547 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl) const
6549 if (nLvl)
6550 --nLvl;
6551 // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6552 if ( sal::static_int_cast< sal_Int32>(nLvl) >= sal::static_int_cast< sal_Int32>(m_aApos.size()) )
6554 return false;
6556 mycApoIter aIter = std::find(m_aApos.begin() + nLvl, m_aApos.end(), true);
6557 if (aIter != m_aApos.end())
6558 return true;
6559 else
6560 return false;
6563 bool SwWW8ImplReader::InEqualApo(int nLvl) const
6565 // If we are in a table, see if an apo was inserted at the level below the table.
6566 if (nLvl)
6567 --nLvl;
6568 if (nLvl < 0 || static_cast<size_t>(nLvl) >= m_aApos.size())
6569 return false;
6570 return m_aApos[nLvl];
6573 namespace sw
6575 namespace hack
6577 Position::Position(const SwPosition &rPos)
6578 : maPtNode(rPos.nNode), mnPtContent(rPos.nContent.GetIndex())
6582 Position::Position(const Position &rPos)
6583 : maPtNode(rPos.maPtNode), mnPtContent(rPos.mnPtContent)
6587 Position::operator SwPosition() const
6589 SwPosition aRet(maPtNode);
6590 aRet.nContent.Assign(maPtNode.GetNode().GetContentNode(), mnPtContent);
6591 return aRet;
6596 SwMacroInfo::SwMacroInfo()
6597 : SdrObjUserData( SdrInventor::ScOrSwDraw, SW_UD_IMAPDATA )
6598 , mnShapeId(-1)
6602 SwMacroInfo::~SwMacroInfo()
6606 SdrObjUserData* SwMacroInfo::Clone( SdrObject* /*pObj*/ ) const
6608 return new SwMacroInfo( *this );
6611 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */