Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx
Warning:line 6304, column 1
Potential leak of memory pointed to by 'xStorage.pObj'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ww8par.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <config_features.h>
21
22#include <sal/config.h>
23#include <sal/log.hxx>
24
25#include <com/sun/star/embed/Aspects.hpp>
26#include <com/sun/star/embed/ElementModes.hpp>
27#include <com/sun/star/frame/XModel.hpp>
28#include <com/sun/star/packages/XPackageEncryption.hpp>
29#include <com/sun/star/lang/XMultiServiceFactory.hpp>
30
31#include <i18nlangtag/languagetag.hxx>
32
33#include <unotools/configmgr.hxx>
34#include <unotools/ucbstreamhelper.hxx>
35#include <unotools/streamwrap.hxx>
36#include <rtl/random.h>
37#include <rtl/ustring.hxx>
38#include <rtl/ustrbuf.hxx>
39
40#include <sfx2/docinf.hxx>
41#include <sfx2/frame.hxx>
42#include <sfx2/zoomitem.hxx>
43#include <tools/urlobj.hxx>
44#include <unotools/tempfile.hxx>
45
46#include <comphelper/docpasswordrequest.hxx>
47#include <comphelper/documentinfo.hxx>
48#include <comphelper/propertysequence.hxx>
49
50#include <editeng/outlobj.hxx>
51#include <editeng/brushitem.hxx>
52#include <editeng/formatbreakitem.hxx>
53#include <editeng/tstpitem.hxx>
54#include <editeng/ulspitem.hxx>
55#include <editeng/langitem.hxx>
56#include <editeng/opaqitem.hxx>
57#include <editeng/charhiddenitem.hxx>
58#include <editeng/fontitem.hxx>
59#include <editeng/editeng.hxx>
60#include <svx/unoapi.hxx>
61#include <svx/svdoole2.hxx>
62#include <svx/svdoashp.hxx>
63#include <svx/svxerr.hxx>
64#include <filter/msfilter/mscodec.hxx>
65#include <svx/svdmodel.hxx>
66#include <svx/xflclit.hxx>
67#include <svx/sdasitm.hxx>
68#include <svx/sdtagitm.hxx>
69#include <svx/sdtcfitm.hxx>
70#include <svx/sdtditm.hxx>
71#include <svx/sdtmfitm.hxx>
72#include <unotools/fltrcfg.hxx>
73#include <fmtfld.hxx>
74#include <fmturl.hxx>
75#include <fmtinfmt.hxx>
76#include <reffld.hxx>
77#include <fmthdft.hxx>
78#include <fmtcntnt.hxx>
79#include <fmtcnct.hxx>
80#include <fmtanchr.hxx>
81#include <fmtpdsc.hxx>
82#include <ftninfo.hxx>
83#include <fmtftn.hxx>
84#include <txtftn.hxx>
85#include <ndtxt.hxx>
86#include <pagedesc.hxx>
87#include <paratr.hxx>
88#include <poolfmt.hxx>
89#include <fmtclbl.hxx>
90#include <section.hxx>
91#include <docsh.hxx>
92#include <IDocumentFieldsAccess.hxx>
93#include <IDocumentLayoutAccess.hxx>
94#include <IDocumentMarkAccess.hxx>
95#include <IDocumentStylePoolAccess.hxx>
96#include <IDocumentExternalData.hxx>
97#include <../../core/inc/DocumentRedlineManager.hxx>
98#include <docufld.hxx>
99#include <swfltopt.hxx>
100#include <viewsh.hxx>
101#include <shellres.hxx>
102#include <swerror.h>
103#include <swtable.hxx>
104#include <fchrfmt.hxx>
105#include <charfmt.hxx>
106#include <IDocumentSettingAccess.hxx>
107#include "sprmids.hxx"
108
109#include "writerwordglue.hxx"
110
111#include <ndgrf.hxx>
112#include <editeng/editids.hrc>
113#include <fmtflcnt.hxx>
114#include <txatbase.hxx>
115
116#include "ww8par2.hxx"
117
118#include <com/sun/star/beans/PropertyAttribute.hpp>
119#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
120#include <com/sun/star/document/XViewDataSupplier.hpp>
121#include <com/sun/star/document/IndexedPropertyValues.hpp>
122
123#include <svl/lngmisc.hxx>
124#include <svl/itemiter.hxx>
125
126#include <comphelper/processfactory.hxx>
127#include <basic/basmgr.hxx>
128
129#include "ww8toolbar.hxx"
130#include <o3tl/safeint.hxx>
131#include <osl/file.hxx>
132
133#include <breakit.hxx>
134
135#if OSL_DEBUG_LEVEL1 > 1
136#include <iostream>
137#include <dbgoutsw.hxx>
138#endif
139
140#include <sfx2/docfile.hxx>
141#include <swdll.hxx>
142#include "WW8Sttbf.hxx"
143#include "WW8FibData.hxx"
144#include <unordered_set>
145#include <memory>
146
147using namespace ::com::sun::star;
148using namespace sw::util;
149using namespace sw::types;
150using namespace nsHdFtFlags;
151
152#include <com/sun/star/i18n/XBreakIterator.hpp>
153#include <com/sun/star/i18n/ScriptType.hpp>
154#include <unotools/pathoptions.hxx>
155#include <com/sun/star/ucb/SimpleFileAccess.hpp>
156
157#include <com/sun/star/script/vba/XVBACompatibility.hpp>
158#include <comphelper/sequenceashashmap.hxx>
159#include <oox/ole/vbaproject.hxx>
160#include <oox/ole/olestorage.hxx>
161#include <comphelper/storagehelper.hxx>
162#include <sfx2/DocumentMetadataAccess.hxx>
163#include <tools/diagnose_ex.h>
164
165static SwMacroInfo* GetMacroInfo( SdrObject* pObj )
166{
167 if ( pObj )
168 {
169 sal_uInt16 nCount = pObj->GetUserDataCount();
170 for( sal_uInt16 i = 0; i < nCount; i++ )
171 {
172 SdrObjUserData* pData = pObj->GetUserData( i );
173 if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw
174 && pData->GetId() == SW_UD_IMAPDATA2)
175 {
176 return dynamic_cast<SwMacroInfo*>(pData);
177 }
178 }
179 SwMacroInfo* pData = new SwMacroInfo;
180 pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
181 return pData;
182 }
183
184 return nullptr;
185};
186
187static void lclGetAbsPath(OUString& rPath, sal_uInt16 nLevel, SwDocShell const * pDocShell)
188{
189 OUStringBuffer aTmpStr;
190 while( nLevel )
191 {
192 aTmpStr.append("../");
193 --nLevel;
194 }
195 if (!aTmpStr.isEmpty())
196 aTmpStr.append(rPath);
197 else
198 aTmpStr = rPath;
199
200 if (!aTmpStr.isEmpty())
201 {
202 bool bWasAbs = false;
203 rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr.makeStringAndClear(), bWasAbs ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
204 // full path as stored in SvxURLField must be encoded
205 }
206}
207
208namespace
209{
210 void lclIgnoreUString32(SvStream& rStrm)
211 {
212 sal_uInt32 nChars(0);
213 rStrm.ReadUInt32(nChars);
214 nChars *= 2;
215 rStrm.SeekRel(nChars);
216 }
217}
218
219void SwWW8ImplReader::ReadEmbeddedData(SvStream& rStrm, SwDocShell const * pDocShell, struct HyperLinksTable& hlStr)
220{
221 // (0x01B8) HLINK
222 // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
223 constexpr sal_uInt32 WW8_HLINK_BODY = 0x00000001; /// Contains file link or URL.
224 constexpr sal_uInt32 WW8_HLINK_ABS = 0x00000002; /// Absolute path.
225 constexpr sal_uInt32 WW8_HLINK_DESCR = 0x00000014; /// Description.
226 constexpr sal_uInt32 WW8_HLINK_MARK = 0x00000008; /// Text mark.
227 constexpr sal_uInt32 WW8_HLINK_FRAME = 0x00000080; /// Target frame.
228 constexpr sal_uInt32 WW8_HLINK_UNC = 0x00000100; /// UNC path.
229
230 //sal_uInt8 maGuidStdLink[ 16 ] ={
231 // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
232
233 sal_uInt8 const aGuidUrlMoniker[ 16 ] = {
234 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
235
236 sal_uInt8 const aGuidFileMoniker[ 16 ] = {
237 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
238
239 sal_uInt8 aGuid[16];
240 sal_uInt32 nFlags(0);
241
242 rStrm.ReadBytes(aGuid, 16);
243 rStrm.SeekRel( 4 );
244 rStrm.ReadUInt32( nFlags );
245
246 std::unique_ptr< OUString > xLongName; // link / file name
247 std::unique_ptr< OUString > xShortName; // 8.3-representation of file name
248 std::unique_ptr< OUString > xTextMark; // text mark
249
250 // description (ignore)
251 if( ::get_flag( nFlags, WW8_HLINK_DESCR ) )
252 lclIgnoreUString32( rStrm );
253
254 // target frame
255 if( ::get_flag( nFlags, WW8_HLINK_FRAME ) )
256 {
257 hlStr.tarFrame = read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm);
258 }
259
260 // UNC path
261 if( ::get_flag( nFlags, WW8_HLINK_UNC ) )
262 {
263 // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
264 // string field, including the null-terminating character.
265 sal_uInt32 nStrLen(0);
266 rStrm.ReadUInt32(nStrLen);
267 if (nStrLen)
268 {
269 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
270 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
271 }
272 lclGetAbsPath( *xLongName, 0 , pDocShell);
273 }
274 // file link or URL
275 else if( ::get_flag( nFlags, WW8_HLINK_BODY ) )
276 {
277 rStrm.ReadBytes(aGuid, 16);
278
279 if( memcmp(aGuid, aGuidFileMoniker, 16) == 0 )
280 {
281 sal_uInt16 nLevel = 0; // counter for level to climb down in path
282 rStrm.ReadUInt16( nLevel );
283 // MS-OSHARED: An unsigned integer that specifies the number of
284 // ANSI characters in ansiPath, including the terminating NULL character
285 sal_uInt32 nUnits = 0;
286 rStrm.ReadUInt32(nUnits);
287 if (nUnits)
288 {
289 OString sStr(read_uInt8s_ToOString(rStrm, nUnits - 1));
290 rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
291 xShortName.reset(new OUString(sStr.getStr(), sStr.getLength(), GetCharSetFromLanguage()));
292 }
293 rStrm.SeekRel( 24 );
294
295 sal_uInt32 nStrLen(0);
296 rStrm.ReadUInt32( nStrLen );
297 if( nStrLen )
298 {
299 nStrLen = 0;
300 rStrm.ReadUInt32( nStrLen );
301 nStrLen /= 2;
302 rStrm.SeekRel( 2 );
303 // MS-OSHARED: This array MUST not include a terminating NULL character.
304 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen)));
305 lclGetAbsPath( *xLongName, nLevel, pDocShell);
306 }
307 else
308 lclGetAbsPath( *xShortName, nLevel, pDocShell);
309 }
310 else if( memcmp(aGuid, aGuidUrlMoniker, 16) == 0 )
311 {
312 // MS-OSHARED: An unsigned integer that specifies the size of this
313 // structure in bytes, excluding the size of the length field. The
314 // value of this field MUST be ... the byte size of the url
315 // field (including the terminating NULL character)
316 sal_uInt32 nStrLen(0);
317 rStrm.ReadUInt32( nStrLen );
318 nStrLen /= 2;
319 if (nStrLen)
320 {
321 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
322 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
323 }
324 if( !::get_flag( nFlags, WW8_HLINK_ABS ) )
325 lclGetAbsPath( *xLongName, 0 ,pDocShell);
326 }
327 else
328 {
329 SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "WW8Hyperlink::ReadEmbeddedData - unknown content GUID"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "329" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "WW8Hyperlink::ReadEmbeddedData - unknown content GUID"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "WW8Hyperlink::ReadEmbeddedData - unknown content GUID"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "329" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "WW8Hyperlink::ReadEmbeddedData - unknown content GUID"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "329" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "WW8Hyperlink::ReadEmbeddedData - unknown content GUID"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "WW8Hyperlink::ReadEmbeddedData - unknown content GUID"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "329" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
330 }
331 }
332
333 // text mark
334 if( ::get_flag( nFlags, WW8_HLINK_MARK ) )
335 {
336 xTextMark.reset(new OUString(read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm)));
337 }
338
339 if (!xLongName && xShortName)
340 {
341 xLongName.reset( new OUString );
342 *xLongName += *xShortName;
343 }
344 else if (!xLongName && xTextMark)
345 xLongName.reset( new OUString );
346
347 if (xLongName)
348 {
349 if (xTextMark)
350 {
351 if (xLongName->isEmpty())
352 *xTextMark = xTextMark->replace('!', '.');
353 *xLongName += "#" + *xTextMark;
354 }
355 hlStr.hLinkAddr = *xLongName;
356 }
357}
358
359namespace {
360
361class BasicProjImportHelper
362{
363 SwDocShell& mrDocShell;
364 uno::Reference< uno::XComponentContext > mxCtx;
365public:
366 explicit BasicProjImportHelper( SwDocShell& rShell ) : mrDocShell( rShell ),
367 mxCtx(comphelper::getProcessComponentContext())
368 {
369 }
370 bool import( const uno::Reference< io::XInputStream >& rxIn );
371 OUString getProjectName() const;
372};
373
374}
375
376bool BasicProjImportHelper::import( const uno::Reference< io::XInputStream >& rxIn )
377{
378 bool bRet = false;
379 try
380 {
381 oox::ole::OleStorage root( mxCtx, rxIn, false );
382 oox::StorageRef vbaStg = root.openSubStorage( "Macros" , false );
383 if ( vbaStg )
384 {
385 oox::ole::VbaProject aVbaPrj( mxCtx, mrDocShell.GetModel(), "Writer" );
386 bRet = aVbaPrj.importVbaProject( *vbaStg );
387 }
388 }
389 catch( const uno::Exception& )
390 {
391 bRet = false;
392 }
393 return bRet;
394}
395
396OUString BasicProjImportHelper::getProjectName() const
397{
398 OUString sProjName( "Standard" );
399 uno::Reference< beans::XPropertySet > xProps( mrDocShell.GetModel(), uno::UNO_QUERY );
400 if ( xProps.is() )
401 {
402 try
403 {
404 uno::Reference< script::vba::XVBACompatibility > xVBA( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
405 sProjName = xVBA->getProjectName();
406
407 }
408 catch( const uno::Exception& )
409 {
410 }
411 }
412 return sProjName;
413}
414
415namespace {
416
417class Sttb : public TBBase
418{
419struct SBBItem
420{
421 sal_uInt16 cchData;
422 OUString data;
423 SBBItem() : cchData(0){}
424};
425 sal_uInt16 fExtend;
426 sal_uInt16 cData;
427 sal_uInt16 cbExtra;
428
429 std::vector< SBBItem > dataItems;
430
431 Sttb(Sttb const&) = delete;
432 Sttb& operator=(Sttb const&) = delete;
433
434public:
435 Sttb();
436
437 bool Read(SvStream &rS) override;
438 OUString getStringAtIndex( sal_uInt32 );
439};
440
441}
442
443Sttb::Sttb()
444 : fExtend(0)
445 , cData(0)
446 , cbExtra(0)
447{
448}
449
450bool Sttb::Read( SvStream& rS )
451{
452 SAL_INFO("sw.ww8", "stream pos " << rS.Tell())do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "stream pos " <<
rS.Tell()) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "452" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "stream pos " << rS.Tell()), 0);
} else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "stream pos " << rS.Tell(); ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "452" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "stream pos " << rS.Tell()) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "452" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "stream pos " << rS.Tell()), 0);
} else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "stream pos " << rS.Tell(); ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "452" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
453 nOffSet = rS.Tell();
454 rS.ReadUInt16( fExtend ).ReadUInt16( cData ).ReadUInt16( cbExtra );
455 if ( cData )
456 {
457 //if they are all going to be empty strings, how many could there be
458 const size_t nMaxPossibleRecords = rS.remainingSize() / sizeof(sal_uInt16);
459 if (cData > nMaxPossibleRecords)
460 return false;
461 for ( sal_Int32 index = 0; index < cData; ++index )
462 {
463 SBBItem aItem;
464 rS.ReadUInt16( aItem.cchData );
465 aItem.data = read_uInt16s_ToOUString(rS, aItem.cchData);
466 dataItems.push_back( aItem );
467 }
468 }
469 return true;
470}
471
472OUString
473Sttb::getStringAtIndex( sal_uInt32 index )
474{
475 OUString aRet;
476 if ( index < dataItems.size() )
477 aRet = dataItems[ index ].data;
478 return aRet;
479
480}
481
482SwMSDffManager::SwMSDffManager( SwWW8ImplReader& rRdr, bool bSkipImages )
483 : SvxMSDffManager(*rRdr.m_pTableStream, rRdr.GetBaseURL(), rRdr.m_xWwFib->m_fcDggInfo,
484 rRdr.m_pDataStream, nullptr, 0, COL_WHITE, rRdr.m_pStrm, bSkipImages),
485 rReader(rRdr), pFallbackStream(nullptr)
486{
487 SetSvxMSDffSettings( GetSvxMSDffSettings() );
488 nSvxMSDffOLEConvFlags = SwMSDffManager::GetFilterFlags();
489}
490
491sal_uInt32 SwMSDffManager::GetFilterFlags()
492{
493 sal_uInt32 nFlags(0);
494 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
495 if (rOpt.IsMathType2Math())
496 nFlags |= OLE_MATHTYPE_2_STARMATH0x0001;
497 if (rOpt.IsExcel2Calc())
498 nFlags |= OLE_EXCEL_2_STARCALC0x0004;
499 if (rOpt.IsPowerPoint2Impress())
500 nFlags |= OLE_POWERPOINT_2_STARIMPRESS0x0008;
501 if (rOpt.IsWinWord2Writer())
502 nFlags |= OLE_WINWORD_2_STARWRITER0x0002;
503 return nFlags;
504}
505
506/*
507 * I would like to override the default OLE importing to add a test
508 * and conversion of OCX controls from their native OLE type into our
509 * native nonOLE Form Control Objects.
510 */
511// #i32596# - consider new parameter <_nCalledByGroup>
512SdrObject* SwMSDffManager::ImportOLE( sal_uInt32 nOLEId,
513 const Graphic& rGrf,
514 const tools::Rectangle& rBoundRect,
515 const tools::Rectangle& rVisArea,
516 const int _nCalledByGroup ) const
517{
518 // #i32596# - no import of OLE object, if it's inside a group.
519 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
520 // if drawing OLE objects are allowed in Writer.
521 if ( _nCalledByGroup > 0 )
522 {
523 return nullptr;
524 }
525
526 SdrObject* pRet = nullptr;
527 OUString sStorageName;
528 tools::SvRef<SotStorage> xSrcStg;
529 uno::Reference < embed::XStorage > xDstStg;
530 if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
531 {
532 tools::SvRef<SotStorage> xSrc = xSrcStg->OpenSotStorage( sStorageName );
533 OSL_ENSURE(rReader.m_xFormImpl, "No Form Implementation!")do { if (true && (!(rReader.m_xFormImpl))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "533" ": "), "%s", "No Form Implementation!"); } } while
(false)
;
534 css::uno::Reference< css::drawing::XShape > xShape;
535 if ( (!(rReader.m_bIsHeader || rReader.m_bIsFooter)) &&
536 rReader.m_xFormImpl->ReadOCXStream(xSrc,&xShape,true))
537 {
538 pRet = GetSdrObjectFromXShape(xShape);
539 }
540 else
541 {
542 ErrCode nError = ERRCODE_NONEErrCode(0);
543 pRet = CreateSdrOLEFromStorage(
544 *pSdrModel,
545 sStorageName,
546 xSrcStg,
547 xDstStg,
548 rGrf,
549 rBoundRect,
550 rVisArea,
551 pStData,
552 nError,
553 nSvxMSDffOLEConvFlags,
554 css::embed::Aspects::MSOLE_CONTENT,
555 rReader.GetBaseURL());
556 }
557 }
558 return pRet;
559}
560
561void SwMSDffManager::DisableFallbackStream()
562{
563 OSL_ENSURE(!pFallbackStream,do { if (true && (!(!pFallbackStream))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "564" ": "), "%s", "if you're recursive, you're broken")
; } } while (false)
564 "if you're recursive, you're broken")do { if (true && (!(!pFallbackStream))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "564" ": "), "%s", "if you're recursive, you're broken")
; } } while (false)
;
565 pFallbackStream = pStData2;
566 aOldEscherBlipCache = aEscherBlipCache;
567 aEscherBlipCache.clear();
568 pStData2 = nullptr;
569}
570
571void SwMSDffManager::EnableFallbackStream()
572{
573 pStData2 = pFallbackStream;
574 aEscherBlipCache = aOldEscherBlipCache;
575 aOldEscherBlipCache.clear();
576 pFallbackStream = nullptr;
577}
578
579sal_uInt16 SwWW8ImplReader::GetToggleAttrFlags() const
580{
581 return m_xCtrlStck ? m_xCtrlStck->GetToggleAttrFlags() : 0;
582}
583
584sal_uInt16 SwWW8ImplReader::GetToggleBiDiAttrFlags() const
585{
586 return m_xCtrlStck ? m_xCtrlStck->GetToggleBiDiAttrFlags() : 0;
587}
588
589void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags)
590{
591 if (m_xCtrlStck)
592 m_xCtrlStck->SetToggleAttrFlags(nFlags);
593}
594
595void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags)
596{
597 if (m_xCtrlStck)
598 m_xCtrlStck->SetToggleBiDiAttrFlags(nFlags);
599}
600
601SdrObject* SwMSDffManager::ProcessObj(SvStream& rSt,
602 DffObjData& rObjData,
603 SvxMSDffClientData& rData,
604 tools::Rectangle& rTextRect,
605 SdrObject* pObj
606 )
607{
608 if( !rTextRect.IsEmpty() )
609 {
610 SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
611 std::unique_ptr<SvxMSDffImportRec> pImpRec(new SvxMSDffImportRec);
612
613 // fill Import Record with data
614 pImpRec->nShapeId = rObjData.nShapeId;
615 pImpRec->eShapeType = rObjData.eShapeType;
616
617 rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
618 DFF_msofbtClientAnchor0xF010,
619 SEEK_FROM_CURRENT_AND_RESTART );
620 if( rObjData.bClientAnchor )
621 ProcessClientAnchor( rSt,
622 maShapeRecords.Current()->nRecLen,
623 pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
624
625 rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
626 DFF_msofbtClientData0xF011,
627 SEEK_FROM_CURRENT_AND_RESTART );
628 if( rObjData.bClientData )
629 ProcessClientData( rSt,
630 maShapeRecords.Current()->nRecLen,
631 pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
632
633 // process user (== Winword) defined parameters in 0xF122 record
634 // #i84783# - set special value to determine, if property is provided or not.
635 pImpRec->nLayoutInTableCell = 0xFFFFFFFF;
636
637 if( maShapeRecords.SeekToContent( rSt,
638 DFF_msofbtUDefProp0xF122,
639 SEEK_FROM_CURRENT_AND_RESTART )
640 && maShapeRecords.Current()->nRecLen )
641 {
642 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
643 auto nAvailableBytes = rSt.remainingSize();
644 if (nBytesLeft > nAvailableBytes)
645 {
646 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft << " bytes, but only " << nAvailableBytes << " available")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Document claimed to have shape record of "
<< nBytesLeft << " bytes, but only " << nAvailableBytes
<< " available") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "646" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Document claimed to have shape record of "
<< nBytesLeft << " bytes, but only " << nAvailableBytes
<< " available"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "Document claimed to have shape record of "
<< nBytesLeft << " bytes, but only " << nAvailableBytes
<< " available"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "646" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Document claimed to have shape record of " <<
nBytesLeft << " bytes, but only " << nAvailableBytes
<< " available") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "646" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Document claimed to have shape record of "
<< nBytesLeft << " bytes, but only " << nAvailableBytes
<< " available"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "Document claimed to have shape record of "
<< nBytesLeft << " bytes, but only " << nAvailableBytes
<< " available"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "646" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
647 nBytesLeft = nAvailableBytes;
648 }
649 while( 5 < nBytesLeft )
650 {
651 sal_uInt16 nPID(0);
652 rSt.ReadUInt16(nPID);
653 sal_uInt32 nUDData(0);
654 rSt.ReadUInt32(nUDData);
655 if (!rSt.good())
656 break;
657 switch (nPID)
658 {
659 case 0x038F: pImpRec->nXAlign = nUDData; break;
660 case 0x0390:
661 pImpRec->nXRelTo = nUDData;
662 break;
663 case 0x0391: pImpRec->nYAlign = nUDData; break;
664 case 0x0392:
665 pImpRec->nYRelTo = nUDData;
666 break;
667 case 0x03BF: pImpRec->nLayoutInTableCell = nUDData; break;
668 case 0x0393:
669 // This seems to correspond to o:hrpct from .docx (even including
670 // the difference that it's in 0.1% even though the .docx spec
671 // says it's in 1%).
672 pImpRec->relativeHorizontalWidth = nUDData;
673 break;
674 case 0x0394:
675 // And this is really just a guess, but a mere presence of this
676 // flag makes a horizontal rule be as wide as the page (unless
677 // overridden by something), so it probably matches o:hr from .docx.
678 pImpRec->isHorizontalRule = true;
679 break;
680 }
681 nBytesLeft -= 6;
682 }
683 }
684
685 // Text Frame also Title or Outline
686 sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid128, 0 );
687 if( nTextId )
688 {
689 SfxItemSet aSet( pSdrModel->GetItemPool() );
690
691 // Originally anything that as a mso_sptTextBox was created as a
692 // textbox, this was changed to be created as a simple
693 // rect to keep impress happy. For the rest of us we'd like to turn
694 // it back into a textbox again.
695 bool bIsSimpleDrawingTextBox = (pImpRec->eShapeType == mso_sptTextBox);
696 if (!bIsSimpleDrawingTextBox)
697 {
698 // Either
699 // a) it's a simple text object or
700 // b) it's a rectangle with text and square wrapping.
701 bIsSimpleDrawingTextBox =
702 (
703 (pImpRec->eShapeType == mso_sptTextSimple) ||
704 (
705 (pImpRec->eShapeType == mso_sptRectangle)
706 && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
707 )
708 );
709 }
710
711 // Distance of Textbox to its surrounding Autoshape
712 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft129, 91440);
713 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight131, 91440 );
714 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop130, 45720 );
715 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom132, 45720 );
716
717 ScaleEmu( nTextLeft );
718 ScaleEmu( nTextRight );
719 ScaleEmu( nTextTop );
720 ScaleEmu( nTextBottom );
721
722 sal_Int32 nTextRotationAngle=0;
723 bool bVerticalText = false;
724 if ( IsProperty( DFF_Prop_txflTextFlow136 ) )
725 {
726 MSO_TextFlow eTextFlow = static_cast<MSO_TextFlow>(GetPropertyValue(
727 DFF_Prop_txflTextFlow136, 0) & 0xFFFF);
728 switch( eTextFlow )
729 {
730 case mso_txflBtoT:
731 nTextRotationAngle = 9000;
732 break;
733 case mso_txflVertN:
734 case mso_txflTtoBN:
735 nTextRotationAngle = 27000;
736 break;
737 case mso_txflTtoBA:
738 bVerticalText = true;
739 break;
740 case mso_txflHorzA:
741 bVerticalText = true;
742 nTextRotationAngle = 9000;
743 break;
744 case mso_txflHorzN:
745 default :
746 break;
747 }
748 }
749
750 if (nTextRotationAngle)
751 {
752 if (nTextRotationAngle == 9000)
753 {
754 long nWidth = rTextRect.GetWidth();
755 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
756 rTextRect.SetBottom( rTextRect.Top() + nWidth );
757
758 sal_Int32 nOldTextLeft = nTextLeft;
759 sal_Int32 nOldTextRight = nTextRight;
760 sal_Int32 nOldTextTop = nTextTop;
761 sal_Int32 nOldTextBottom = nTextBottom;
762
763 nTextLeft = nOldTextBottom;
764 nTextRight = nOldTextTop;
765 nTextTop = nOldTextLeft;
766 nTextBottom = nOldTextRight;
767 }
768 else if (nTextRotationAngle == 27000)
769 {
770 long nWidth = rTextRect.GetWidth();
771 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
772 rTextRect.SetBottom( rTextRect.Top() + nWidth );
773
774 sal_Int32 nOldTextLeft = nTextLeft;
775 sal_Int32 nOldTextRight = nTextRight;
776 sal_Int32 nOldTextTop = nTextTop;
777 sal_Int32 nOldTextBottom = nTextBottom;
778
779 nTextLeft = nOldTextTop;
780 nTextRight = nOldTextBottom;
781 nTextTop = nOldTextRight;
782 nTextBottom = nOldTextLeft;
783 }
784 }
785
786 if (bIsSimpleDrawingTextBox)
787 {
788 SdrObject::Free( pObj );
789 pObj = new SdrRectObj(
790 *pSdrModel,
791 OBJ_TEXT,
792 rTextRect);
793 }
794
795 // The vertical paragraph justification are contained within the
796 // BoundRect so calculate it here
797 tools::Rectangle aNewRect(rTextRect);
798 aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
799 aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
800
801 // Only if it's a simple Textbox, Writer can replace the Object
802 // with a Frame, else
803 if( bIsSimpleDrawingTextBox )
804 {
805 std::shared_ptr<SvxMSDffShapeInfo> const xTmpRec =
806 std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
807
808 SvxMSDffShapeInfos_ById::const_iterator const it =
809 GetShapeInfos()->find(xTmpRec);
810 if (it != GetShapeInfos()->end())
811 {
812 SvxMSDffShapeInfo& rInfo = **it;
813 pImpRec->bReplaceByFly = rInfo.bReplaceByFly;
814 }
815
816 ApplyAttributes(rSt, aSet, rObjData);
817 }
818
819 if (GetPropertyValue(DFF_Prop_FitTextToShape191, 0) & 2)
820 {
821 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
822 aSet.Put( makeSdrTextMinFrameHeightItem(
823 aNewRect.Bottom() - aNewRect.Top() ) );
824 aSet.Put( makeSdrTextMinFrameWidthItem(
825 aNewRect.Right() - aNewRect.Left() ) );
826 }
827 else
828 {
829 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
830 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
831 }
832
833 switch ( static_cast<MSO_WrapMode>(GetPropertyValue( DFF_Prop_WrapText133, mso_wrapSquare )) )
834 {
835 case mso_wrapNone :
836 aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
837 pImpRec->bAutoWidth = true;
838 break;
839 case mso_wrapByPoints :
840 aSet.Put( makeSdrTextContourFrameItem( true ) );
841 break;
842 default:
843 ;
844 }
845
846 // Set distances on Textbox's margins
847 aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
848 aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
849 aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
850 aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
851 pImpRec->nDxTextLeft = nTextLeft;
852 pImpRec->nDyTextTop = nTextTop;
853 pImpRec->nDxTextRight = nTextRight;
854 pImpRec->nDyTextBottom = nTextBottom;
855
856 // Taking the correct default (which is mso_anchorTop)
857 sal_uInt32 eTextAnchor =
858 GetPropertyValue( DFF_Prop_anchorText135, mso_anchorTop );
859
860 SdrTextVertAdjust eTVA = bVerticalText
861 ? SDRTEXTVERTADJUST_BLOCK
862 : SDRTEXTVERTADJUST_CENTER;
863 SdrTextHorzAdjust eTHA = bVerticalText
864 ? SDRTEXTHORZADJUST_CENTER
865 : SDRTEXTHORZADJUST_BLOCK;
866
867 switch( eTextAnchor )
868 {
869 case mso_anchorTop:
870 {
871 if ( bVerticalText )
872 eTHA = SDRTEXTHORZADJUST_RIGHT;
873 else
874 eTVA = SDRTEXTVERTADJUST_TOP;
875 }
876 break;
877 case mso_anchorTopCentered:
878 {
879 if ( bVerticalText )
880 eTHA = SDRTEXTHORZADJUST_RIGHT;
881 else
882 eTVA = SDRTEXTVERTADJUST_TOP;
883 }
884 break;
885 case mso_anchorMiddle:
886 break;
887 case mso_anchorMiddleCentered:
888 break;
889 case mso_anchorBottom:
890 {
891 if ( bVerticalText )
892 eTHA = SDRTEXTHORZADJUST_LEFT;
893 else
894 eTVA = SDRTEXTVERTADJUST_BOTTOM;
895 }
896 break;
897 case mso_anchorBottomCentered:
898 {
899 if ( bVerticalText )
900 eTHA = SDRTEXTHORZADJUST_LEFT;
901 else
902 eTVA = SDRTEXTVERTADJUST_BOTTOM;
903 }
904 break;
905 default:
906 ;
907 }
908
909 aSet.Put( SdrTextVertAdjustItem( eTVA ) );
910 aSet.Put( SdrTextHorzAdjustItem( eTHA ) );
911
912 if (pObj != nullptr)
913 {
914 pObj->SetMergedItemSet(aSet);
915
916 if (bVerticalText)
917 {
918 SdrTextObj *pTextObj = dynamic_cast< SdrTextObj* >(pObj);
919 if (pTextObj)
920 pTextObj->SetVerticalWriting(true);
921 }
922
923 if ( bIsSimpleDrawingTextBox )
924 {
925 if ( nTextRotationAngle )
926 {
927 long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
928 rTextRect.GetWidth() : rTextRect.GetHeight();
929 nMinWH /= 2;
930 Point aPivot(rTextRect.TopLeft());
931 aPivot.AdjustX(nMinWH );
932 aPivot.AdjustY(nMinWH );
933 double a = nTextRotationAngle * F_PI18000(3.14159265358979323846/18000.0);
934 pObj->NbcRotate(aPivot, nTextRotationAngle, sin(a), cos(a));
935 }
936 }
937
938 if ( ( ( rObjData.nSpFlags & ShapeFlag::FlipV ) || mnFix16Angle || nTextRotationAngle ) && dynamic_cast< SdrObjCustomShape* >( pObj ) )
939 {
940 SdrObjCustomShape* pCustomShape = dynamic_cast< SdrObjCustomShape* >( pObj );
941 if (pCustomShape)
942 {
943 double fExtraTextRotation = 0.0;
944 if ( mnFix16Angle && !( GetPropertyValue( DFF_Prop_FitTextToShape191, 0 ) & 4 ) )
945 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
946 fExtraTextRotation = -mnFix16Angle;
947 }
948 if ( rObjData.nSpFlags & ShapeFlag::FlipV ) // sj: in ppt the text is flipped, whereas in word the text
949 { // remains unchanged, so we have to take back the flipping here
950 fExtraTextRotation += 18000.0; // because our core will flip text if the shape is flipped.
951 }
952 fExtraTextRotation += nTextRotationAngle;
953 if ( !::basegfx::fTools::equalZero( fExtraTextRotation ) )
954 {
955 fExtraTextRotation /= 100.0;
956 SdrCustomShapeGeometryItem aGeometryItem( pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
957 css::beans::PropertyValue aPropVal;
958 aPropVal.Name = "TextRotateAngle";
959 aPropVal.Value <<= fExtraTextRotation;
960 aGeometryItem.SetPropertyValue( aPropVal );
961 pCustomShape->SetMergedItem( aGeometryItem );
962 }
963 }
964 }
965 else if ( mnFix16Angle )
966 {
967 // rotate text with shape ?
968 double a = mnFix16Angle * F_PI18000(3.14159265358979323846/18000.0);
969 pObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
970 sin( a ), cos( a ) );
971 }
972 }
973 }
974 else if( !pObj )
975 {
976 // simple rectangular objects are ignored by ImportObj() :-(
977 // this is OK for Draw but not for Calc and Writer
978 // cause here these objects have a default border
979 pObj = new SdrRectObj(
980 *pSdrModel,
981 rTextRect);
982
983 SfxItemSet aSet( pSdrModel->GetItemPool() );
984 ApplyAttributes( rSt, aSet, rObjData );
985
986 const SfxPoolItem* pPoolItem=nullptr;
987 SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR,
988 false, &pPoolItem );
989 if( SfxItemState::DEFAULT == eState )
990 aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
991 pObj->SetMergedItemSet(aSet);
992 }
993
994 // Means that fBehindDocument is set
995 if (GetPropertyValue(DFF_Prop_fPrint959, 0) & 0x20)
996 pImpRec->bDrawHell = true;
997 else
998 pImpRec->bDrawHell = false;
999 if (GetPropertyValue(DFF_Prop_fPrint959, 0) & 0x02)
1000 pImpRec->bHidden = true;
1001 pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext138, 0 );
1002
1003 if ( nTextId )
1004 {
1005 pImpRec->aTextId.nTxBxS = static_cast<sal_uInt16>( nTextId >> 16 );
1006 pImpRec->aTextId.nSequence = static_cast<sal_uInt16>(nTextId);
1007 }
1008
1009 pImpRec->nDxWrapDistLeft = GetPropertyValue(
1010 DFF_Prop_dxWrapDistLeft900, 114935 ) / 635;
1011 pImpRec->nDyWrapDistTop = GetPropertyValue(
1012 DFF_Prop_dyWrapDistTop901, 0 ) / 635;
1013 pImpRec->nDxWrapDistRight = GetPropertyValue(
1014 DFF_Prop_dxWrapDistRight902, 114935 ) / 635;
1015 pImpRec->nDyWrapDistBottom = GetPropertyValue(
1016 DFF_Prop_dyWrapDistBottom903, 0 ) / 635;
1017 // 16.16 fraction times total image width or height, as appropriate.
1018
1019 if (SeekToContent(DFF_Prop_pWrapPolygonVertices899, rSt))
1020 {
1021 pImpRec->pWrapPolygon.reset();
1022
1023 sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1024 rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
1025 bool bOk = false;
1026 if (nNumElemVert && ((nElemSizeVert == 8) || (nElemSizeVert == 4)))
1027 {
1028 //check if there is enough data in the file to make the
1029 //record sane
1030 bOk = rSt.remainingSize() / nElemSizeVert >= nNumElemVert;
1031 }
1032 if (bOk)
1033 {
1034 pImpRec->pWrapPolygon.reset( new tools::Polygon(nNumElemVert) );
1035 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
1036 {
1037 sal_Int32 nX(0), nY(0);
1038 if (nElemSizeVert == 8)
1039 rSt.ReadInt32( nX ).ReadInt32( nY );
1040 else
1041 {
1042 sal_Int16 nSmallX(0), nSmallY(0);
1043 rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
1044 nX = nSmallX;
1045 nY = nSmallY;
1046 }
1047 (*(pImpRec->pWrapPolygon))[i].setX( nX );
1048 (*(pImpRec->pWrapPolygon))[i].setY( nY );
1049 }
1050 }
1051 }
1052
1053 pImpRec->nCropFromTop = GetPropertyValue(
1054 DFF_Prop_cropFromTop256, 0 );
1055 pImpRec->nCropFromBottom = GetPropertyValue(
1056 DFF_Prop_cropFromBottom257, 0 );
1057 pImpRec->nCropFromLeft = GetPropertyValue(
1058 DFF_Prop_cropFromLeft258, 0 );
1059 pImpRec->nCropFromRight = GetPropertyValue(
1060 DFF_Prop_cropFromRight259, 0 );
1061
1062 sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash511, 0 );
1063
1064 if ( !IsHardAttribute( DFF_Prop_fLine508 ) &&
1065 pImpRec->eShapeType == mso_sptPictureFrame )
1066 {
1067 nLineFlags &= ~0x08;
1068 }
1069
1070 pImpRec->eLineStyle = (nLineFlags & 8)
1071 ? static_cast<MSO_LineStyle>(GetPropertyValue(
1072 DFF_Prop_lineStyle461,
1073 mso_lineSimple ))
1074 : MSO_LineStyle(USHRT_MAX(32767 *2 +1));
1075 pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
1076 DFF_Prop_lineDashing462, mso_lineSolid ));
1077
1078 pImpRec->nFlags = rObjData.nSpFlags;
1079
1080 if( pImpRec->nShapeId )
1081 {
1082 auto nShapeId = pImpRec->nShapeId;
1083 auto nShapeOrder = (static_cast<sal_uLong>(pImpRec->aTextId.nTxBxS) << 16)
1084 + pImpRec->aTextId.nSequence;
1085 // Complement Import Record List
1086 pImpRec->pObj = pObj;
1087 rImportData.insert(std::move(pImpRec));
1088
1089 // Complement entry in Z Order List with a pointer to this Object
1090 // Only store objects which are not deep inside the tree
1091 if( ( rObjData.nCalledByGroup == 0 )
1092 ||
1093 ( (rObjData.nSpFlags & ShapeFlag::Group)
1094 && (rObjData.nCalledByGroup < 2) )
1095 )
1096 {
1097 StoreShapeOrder(nShapeId, nShapeOrder, pObj);
1098 }
1099 }
1100 else
1101 pImpRec.reset();
1102 }
1103
1104 sal_uInt32 nBufferSize = GetPropertyValue( DFF_Prop_pihlShape898, 0 );
1105 if( (0 < nBufferSize) && (nBufferSize <= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape898, rSt ) )
1106 {
1107 SvMemoryStream aMemStream;
1108 struct HyperLinksTable hlStr;
1109 aMemStream.WriteUInt16( 0 ).WriteUInt16( nBufferSize );
1110
1111 // copy from DFF stream to memory stream
1112 std::vector< sal_uInt8 > aBuffer( nBufferSize );
1113 if (rSt.ReadBytes(aBuffer.data(), nBufferSize) == nBufferSize)
1114 {
1115 aMemStream.WriteBytes(aBuffer.data(), nBufferSize);
1116 sal_uInt8 nStreamSize = aMemStream.TellEnd();
1117 aMemStream.Seek( STREAM_SEEK_TO_BEGIN0L );
1118 bool bRet = 4 <= nStreamSize;
1119 sal_uInt16 nRawRecId,nRawRecSize;
1120 if( bRet )
1121 aMemStream.ReadUInt16( nRawRecId ).ReadUInt16( nRawRecSize );
1122 SwDocShell* pDocShell = rReader.m_pDocShell;
1123 if (pDocShell)
1124 {
1125 rReader.ReadEmbeddedData(aMemStream, pDocShell, hlStr);
1126 }
1127 }
1128
1129 if (pObj && !hlStr.hLinkAddr.isEmpty())
1130 {
1131 SwMacroInfo* pInfo = GetMacroInfo( pObj );
1132 if( pInfo )
1133 {
1134 pInfo->SetShapeId( rObjData.nShapeId );
1135 pInfo->SetHlink( hlStr.hLinkAddr );
1136 if (!hlStr.tarFrame.isEmpty())
1137 pInfo->SetTarFrame( hlStr.tarFrame );
1138 OUString aNameStr = GetPropertyString( DFF_Prop_wzName896, rSt );
1139 if (!aNameStr.isEmpty())
1140 pInfo->SetName( aNameStr );
1141 }
1142 }
1143 }
1144
1145 return pObj;
1146}
1147
1148/**
1149 * Special FastSave - Attributes
1150 */
1151void SwWW8ImplReader::Read_StyleCode( sal_uInt16, const sal_uInt8* pData, short nLen )
1152{
1153 if (nLen < 0)
1154 {
1155 m_bCpxStyle = false;
1156 return;
1157 }
1158 sal_uInt16 nColl = 0;
1159 if (m_xWwFib->GetFIBVersion() <= ww::eWW2)
1160 nColl = *pData;
1161 else
1162 nColl = SVBT16ToUInt16(pData);
1163 if (nColl < m_vColl.size())
1164 {
1165 SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[nColl] );
1166 m_bCpxStyle = true;
1167 }
1168}
1169
1170/**
1171 * Read_Majority is for Majority (103) and Majority50 (108)
1172 */
1173void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short )
1174{
1175}
1176
1177/**
1178 * Stack
1179 */
1180void SwWW8FltControlStack::NewAttr(const SwPosition& rPos,
1181 const SfxPoolItem& rAttr)
1182{
1183 OSL_ENSURE(RES_TXTATR_FIELD != rAttr.Which(), "probably don't want to put"do { if (true && (!(RES_TXTATR_FIELD != rAttr.Which()
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1184" ": "), "%s", "probably don't want to put" "fields into the control stack"
); } } while (false)
1184 "fields into the control stack")do { if (true && (!(RES_TXTATR_FIELD != rAttr.Which()
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1184" ": "), "%s", "probably don't want to put" "fields into the control stack"
); } } while (false)
;
1185 OSL_ENSURE(RES_TXTATR_INPUTFIELD != rAttr.Which(), "probably don't want to put"do { if (true && (!(RES_TXTATR_INPUTFIELD != rAttr.Which
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1186" ": "), "%s", "probably don't want to put" "input fields into the control stack"
); } } while (false)
1186 "input fields into the control stack")do { if (true && (!(RES_TXTATR_INPUTFIELD != rAttr.Which
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1186" ": "), "%s", "probably don't want to put" "input fields into the control stack"
); } } while (false)
;
1187 OSL_ENSURE(RES_TXTATR_ANNOTATION != rAttr.Which(), "probably don't want to put"do { if (true && (!(RES_TXTATR_ANNOTATION != rAttr.Which
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1188" ": "), "%s", "probably don't want to put" "annotations into the control stack"
); } } while (false)
1188 "annotations into the control stack")do { if (true && (!(RES_TXTATR_ANNOTATION != rAttr.Which
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1188" ": "), "%s", "probably don't want to put" "annotations into the control stack"
); } } while (false)
;
1189 OSL_ENSURE(RES_FLTR_REDLINE != rAttr.Which(), "probably don't want to put"do { if (true && (!(RES_FLTR_REDLINE != rAttr.Which()
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1190" ": "), "%s", "probably don't want to put" "redlines into the control stack"
); } } while (false)
1190 "redlines into the control stack")do { if (true && (!(RES_FLTR_REDLINE != rAttr.Which()
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1190" ": "), "%s", "probably don't want to put" "redlines into the control stack"
); } } while (false)
;
1191 SwFltControlStack::NewAttr(rPos, rAttr);
1192}
1193
1194SwFltStackEntry* SwWW8FltControlStack::SetAttr(const SwPosition& rPos, sal_uInt16 nAttrId,
1195 bool bTstEnd, long nHand, bool )
1196{
1197 SwFltStackEntry *pRet = nullptr;
1198 // Doing a textbox, and using the control stack only as a temporary
1199 // collection point for properties which will are not to be set into
1200 // the real document
1201 if (rReader.m_xPlcxMan && rReader.m_xPlcxMan->GetDoingDrawTextBox())
1202 {
1203 size_t nCnt = size();
1204 for (size_t i=0; i < nCnt; ++i)
1205 {
1206 SwFltStackEntry& rEntry = (*this)[i];
1207 if (nAttrId == rEntry.pAttr->Which())
1208 {
1209 DeleteAndDestroy(i--);
1210 --nCnt;
1211 }
1212 }
1213 }
1214 else // Normal case, set the attribute into the document
1215 pRet = SwFltControlStack::SetAttr(rPos, nAttrId, bTstEnd, nHand);
1216 return pRet;
1217}
1218
1219long GetListFirstLineIndent(const SwNumFormat &rFormat)
1220{
1221 OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,do { if (true && (!(rFormat.GetPositionAndSpaceMode()
== SvxNumberFormat::LABEL_WIDTH_AND_POSITION))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1222" ": "), "%s", "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"
); } } while (false)
1222 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" )do { if (true && (!(rFormat.GetPositionAndSpaceMode()
== SvxNumberFormat::LABEL_WIDTH_AND_POSITION))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1222" ": "), "%s", "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"
); } } while (false)
;
1223
1224 SvxAdjust eAdj = rFormat.GetNumAdjust();
1225 long nReverseListIndented;
1226 if (eAdj == SvxAdjust::Right)
1227 nReverseListIndented = -rFormat.GetCharTextDistance();
1228 else if (eAdj == SvxAdjust::Center)
1229 nReverseListIndented = rFormat.GetFirstLineOffset()/2;
1230 else
1231 nReverseListIndented = rFormat.GetFirstLineOffset();
1232 return nReverseListIndented;
1233}
1234
1235static long lcl_GetTrueMargin(const SvxLRSpaceItem &rLR, const SwNumFormat &rFormat,
1236 long &rFirstLinePos)
1237{
1238 OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,do { if (true && (!(rFormat.GetPositionAndSpaceMode()
== SvxNumberFormat::LABEL_WIDTH_AND_POSITION))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1239" ": "), "%s", "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"
); } } while (false)
1239 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" )do { if (true && (!(rFormat.GetPositionAndSpaceMode()
== SvxNumberFormat::LABEL_WIDTH_AND_POSITION))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1239" ": "), "%s", "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"
); } } while (false)
;
1240
1241 const long nBodyIndent = rLR.GetTextLeft();
1242 const long nFirstLineDiff = rLR.GetTextFirstLineOffset();
1243 rFirstLinePos = nBodyIndent + nFirstLineDiff;
1244
1245 const auto nPseudoListBodyIndent = rFormat.GetAbsLSpace();
1246 const long nReverseListIndented = GetListFirstLineIndent(rFormat);
1247 long nExtraListIndent = nPseudoListBodyIndent + nReverseListIndented;
1248
1249 return std::max<long>(nExtraListIndent, 0);
1250}
1251
1252// #i103711#
1253// #i105414#
1254void SyncIndentWithList( SvxLRSpaceItem &rLR,
1255 const SwNumFormat &rFormat,
1256 const bool bFirstLineOfstSet,
1257 const bool bLeftIndentSet )
1258{
1259 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1260 {
1261 long nWantedFirstLinePos;
1262 long nExtraListIndent = lcl_GetTrueMargin(rLR, rFormat, nWantedFirstLinePos);
1263 rLR.SetTextLeft(nWantedFirstLinePos - nExtraListIndent);
1264 rLR.SetTextFirstLineOffset(0);
1265 }
1266 else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1267 {
1268 if ( !bFirstLineOfstSet && bLeftIndentSet &&
1269 rFormat.GetFirstLineIndent() != 0 )
1270 {
1271 rLR.SetTextFirstLineOffset( rFormat.GetFirstLineIndent() );
1272 }
1273 else if ( bFirstLineOfstSet && !bLeftIndentSet &&
1274 rFormat.GetIndentAt() != 0 )
1275 {
1276 rLR.SetTextLeft( rFormat.GetIndentAt() );
1277 }
1278 else if (!bFirstLineOfstSet && !bLeftIndentSet )
1279 {
1280 if ( rFormat.GetFirstLineIndent() != 0 )
1281 {
1282 rLR.SetTextFirstLineOffset( rFormat.GetFirstLineIndent() );
1283 }
1284 if ( rFormat.GetIndentAt() != 0 )
1285 {
1286 rLR.SetTextLeft( rFormat.GetIndentAt() );
1287 }
1288 }
1289 }
1290}
1291
1292const SwNumFormat* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition &rPos,
1293 const SwTextNode &rTextNode)
1294{
1295 const SwNumFormat *pRet = nullptr;
1296 const SfxPoolItem *pItem = GetStackAttr(rPos, RES_FLTR_NUMRULE);
1297 if (pItem && rTextNode.GetNumRule())
1298 {
1299 if (rTextNode.IsCountedInList())
1300 {
1301 OUString sName(static_cast<const SfxStringItem*>(pItem)->GetValue());
1302 const SwNumRule *pRule = rDoc.FindNumRulePtr(sName);
1303 if (pRule)
1304 pRet = GetNumFormatFromSwNumRuleLevel(*pRule, rTextNode.GetActualListLevel());
1305 }
1306 }
1307 return pRet;
1308}
1309
1310sal_Int32 SwWW8FltControlStack::GetCurrAttrCP() const
1311{
1312 return rReader.GetCurrAttrCP();
1313}
1314
1315bool SwWW8FltControlStack::IsParaEndInCPs(sal_Int32 nStart,sal_Int32 nEnd,bool bSdOD) const
1316{
1317 return rReader.IsParaEndInCPs(nStart,nEnd,bSdOD);
1318}
1319
1320/**
1321 * Clear the para end position recorded in reader intermittently
1322 * for the least impact on loading performance.
1323 */
1324void SwWW8FltControlStack::ClearParaEndPosition()
1325{
1326 if ( !empty() )
1327 return;
1328
1329 rReader.ClearParaEndPosition();
1330}
1331
1332bool SwWW8FltControlStack::CheckSdOD(sal_Int32 nStart,sal_Int32 nEnd)
1333{
1334 return rReader.IsParaEndInCPs(nStart,nEnd);
1335}
1336
1337void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition& rTmpPos,
1338 SwFltStackEntry& rEntry )
1339{
1340 switch( rEntry.pAttr->Which() )
1341 {
1342 case RES_FLTR_BOOKMARK:
1343 {
1344 // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1345 // and which is not referenced.
1346 bool bInsertBookmarkIntoDoc = true;
1347
1348 SwFltBookmark* pFltBookmark = dynamic_cast<SwFltBookmark*>(rEntry.pAttr.get());
1349 if ( pFltBookmark != nullptr && pFltBookmark->IsTOCBookmark() )
1350 {
1351 const OUString& rName = pFltBookmark->GetName();
1352 std::set< OUString, SwWW8::ltstr >::const_iterator aResult = aReferencedTOCBookmarks.find(rName);
1353 if ( aResult == aReferencedTOCBookmarks.end() )
1354 {
1355 bInsertBookmarkIntoDoc = false;
1356 }
1357 }
1358 if ( bInsertBookmarkIntoDoc )
1359 {
1360 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1361 }
1362 break;
1363 }
1364 default:
1365 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1366 break;
1367 }
1368
1369}
1370
1371void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos,
1372 SwFltStackEntry& rEntry)
1373{
1374 switch (rEntry.pAttr->Which())
1375 {
1376 case RES_LR_SPACE:
1377 {
1378 /*
1379 Loop over the affected nodes and
1380 a) convert the word style absolute indent to indent relative
1381 to any numbering indent active on the nodes
1382 b) adjust the writer style tabstops relative to the old
1383 paragraph indent to be relative to the new paragraph indent
1384 */
1385 SwPaM aRegion(rTmpPos);
1386 if (rEntry.MakeRegion(rDoc, aRegion, SwFltStackEntry::RegionMode::NoCheck))
1387 {
1388 SvxLRSpaceItem aNewLR( *static_cast<SvxLRSpaceItem*>(rEntry.pAttr.get()) );
1389 sal_uLong nStart = aRegion.Start()->nNode.GetIndex();
1390 sal_uLong nEnd = aRegion.End()->nNode.GetIndex();
1391 for(; nStart <= nEnd; ++nStart)
1392 {
1393 SwNode* pNode = rDoc.GetNodes()[ nStart ];
1394 if (!pNode || !pNode->IsTextNode())
1395 continue;
1396
1397 SwContentNode* pNd = static_cast<SwContentNode*>(pNode);
1398 SvxLRSpaceItem aOldLR = static_cast<const SvxLRSpaceItem&>(pNd->GetAttr(RES_LR_SPACE));
1399
1400 SwTextNode *pTextNode = static_cast<SwTextNode*>(pNode);
1401
1402 const SwNumFormat* pNum
1403 = GetNumFormatFromStack(*aRegion.GetPoint(), *pTextNode);
1404 if (!pNum)
1405 {
1406 pNum = GetNumFormatFromTextNode(*pTextNode);
1407 }
1408
1409 if ( pNum )
1410 {
1411 // #i103711#
1412 const bool bFirstLineIndentSet =
1413 ( rReader.m_aTextNodesHavingFirstLineOfstSet.end() !=
1414 rReader.m_aTextNodesHavingFirstLineOfstSet.find( pNode ) );
1415 // #i105414#
1416 const bool bLeftIndentSet =
1417 ( rReader.m_aTextNodesHavingLeftIndentSet.end() !=
1418 rReader.m_aTextNodesHavingLeftIndentSet.find( pNode ) );
1419 SyncIndentWithList( aNewLR, *pNum,
1420 bFirstLineIndentSet,
1421 bLeftIndentSet );
1422 }
1423
1424 if (aNewLR == aOldLR)
1425 continue;
1426
1427 pNd->SetAttr(aNewLR);
1428
1429 }
1430 }
1431 }
1432 break;
1433
1434 case RES_TXTATR_FIELD:
1435 OSL_ENSURE(false, "What is a field doing in the control stack,"do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1436" ": "), "%s", "What is a field doing in the control stack,"
"probably should have been in the endstack"); } } while (false
)
1436 "probably should have been in the endstack")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1436" ": "), "%s", "What is a field doing in the control stack,"
"probably should have been in the endstack"); } } while (false
)
;
1437 break;
1438
1439 case RES_TXTATR_ANNOTATION:
1440 OSL_ENSURE(false, "What is an annotation doing in the control stack,"do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1441" ": "), "%s", "What is an annotation doing in the control stack,"
"probably should have been in the endstack"); } } while (false
)
1441 "probably should have been in the endstack")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1441" ": "), "%s", "What is an annotation doing in the control stack,"
"probably should have been in the endstack"); } } while (false
)
;
1442 break;
1443
1444 case RES_TXTATR_INPUTFIELD:
1445 OSL_ENSURE(false, "What is an input field doing in the control stack,"do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1446" ": "), "%s", "What is an input field doing in the control stack,"
"probably should have been in the endstack"); } } while (false
)
1446 "probably should have been in the endstack")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1446" ": "), "%s", "What is an input field doing in the control stack,"
"probably should have been in the endstack"); } } while (false
)
;
1447 break;
1448
1449 case RES_TXTATR_INETFMT:
1450 {
1451 SwPaM aRegion(rTmpPos);
1452 if (rEntry.MakeRegion(rDoc, aRegion, SwFltStackEntry::RegionMode::NoCheck))
1453 {
1454 SwFrameFormat *pFrame;
1455 // If we have just one single inline graphic then
1456 // don't insert a field for the single frame, set
1457 // the frames hyperlink field attribute directly.
1458 pFrame = SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion);
1459 if (nullptr != pFrame)
1460 {
1461 const SwFormatINetFormat *pAttr = static_cast<const SwFormatINetFormat *>(
1462 rEntry.pAttr.get());
1463 SwFormatURL aURL;
1464 aURL.SetURL(pAttr->GetValue(), false);
1465 aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1466 pFrame->SetFormatAttr(aURL);
1467 }
1468 else
1469 {
1470 rDoc.getIDocumentContentOperations().InsertPoolItem(aRegion, *rEntry.pAttr);
1471 }
1472 }
1473 }
1474 break;
1475 default:
1476 SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1477 break;
1478 }
1479}
1480
1481const SfxPoolItem* SwWW8FltControlStack::GetFormatAttr(const SwPosition& rPos,
1482 sal_uInt16 nWhich)
1483{
1484 const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1485 if (!pItem)
1486 {
1487 SwContentNode const*const pNd = rPos.nNode.GetNode().GetContentNode();
1488 if (!pNd)
1489 pItem = &rDoc.GetAttrPool().GetDefaultItem(nWhich);
1490 else
1491 {
1492 /*
1493 If we're hunting for the indent on a paragraph and need to use the
1494 parent style indent, then return the indent in msword format, and
1495 not writer format, because that's the style that the filter works
1496 in (naturally)
1497 */
1498 if (nWhich == RES_LR_SPACE)
1499 {
1500 SfxItemState eState = SfxItemState::DEFAULT;
1501 if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1502 eState = pSet->GetItemState(RES_LR_SPACE, false);
1503 if (eState != SfxItemState::SET && rReader.m_nCurrentColl < rReader.m_vColl.size())
1504 pItem = rReader.m_vColl[rReader.m_nCurrentColl].maWordLR.get();
1505 }
1506
1507 /*
1508 If we're hunting for a character property, try and exact position
1509 within the text node for lookup
1510 */
1511 if (pNd->IsTextNode())
1512 {
1513 const sal_Int32 nPos = rPos.nContent.GetIndex();
1514 m_xScratchSet.reset(new SfxItemSet(rDoc.GetAttrPool(), {{nWhich, nWhich}}));
1515 if (pNd->GetTextNode()->GetParaAttr(*m_xScratchSet, nPos, nPos))
1516 pItem = m_xScratchSet->GetItem(nWhich);
1517 }
1518
1519 if (!pItem)
1520 pItem = &pNd->GetAttr(nWhich);
1521 }
1522 }
1523 return pItem;
1524}
1525
1526const SfxPoolItem* SwWW8FltControlStack::GetStackAttr(const SwPosition& rPos,
1527 sal_uInt16 nWhich)
1528{
1529 SwFltPosition aFltPos(rPos);
1530
1531 size_t nSize = size();
1532 while (nSize)
1533 {
1534 const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1535 if (rEntry.pAttr->Which() == nWhich)
1536 {
1537 if ( (rEntry.bOpen) ||
1538 (
1539 (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1540 (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1541 (rEntry.m_aMkPos.m_nContent <= aFltPos.m_nContent) &&
1542 (rEntry.m_aPtPos.m_nContent > aFltPos.m_nContent)
1543 )
1544 )
1545 /*
1546 * e.g. half-open range [0-3) so asking for properties at 3
1547 * means props that end at 3 are not included
1548 */
1549 {
1550 return rEntry.pAttr.get();
1551 }
1552 }
1553 }
1554 return nullptr;
1555}
1556
1557bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1558 const SwFormatField& rFormatField,
1559 sal_uInt16& rBkmNo)
1560{
1561 const SwField* pField = rFormatField.GetField();
1562 sal_uInt16 nSubType;
1563 if(pField && (SwFieldIds::GetRef == pField->Which())
1564 && ((REF_FOOTNOTE == (nSubType = pField->GetSubType())) || (REF_ENDNOTE == nSubType))
1565 && !static_cast<const SwGetRefField*>(pField)->GetSetRefName().isEmpty())
1566 {
1567 const IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
1568 IDocumentMarkAccess::const_iterator_t ppBkmk =
1569 pMarkAccess->findMark( static_cast<const SwGetRefField*>(pField)->GetSetRefName() );
1570 if(ppBkmk != pMarkAccess->getAllMarksEnd())
1571 {
1572 // find Sequence No of corresponding Foot-/Endnote
1573 rBkmNo = ppBkmk - pMarkAccess->getAllMarksBegin();
1574 return true;
1575 }
1576 }
1577 return false;
1578}
1579
1580void SwWW8FltRefStack::SetAttrInDoc(const SwPosition& rTmpPos,
1581 SwFltStackEntry& rEntry)
1582{
1583 switch (rEntry.pAttr->Which())
1584 {
1585 /*
1586 Look up these in our lists of bookmarks that were changed to
1587 variables, and replace the ref field with a var field, otherwise
1588 do normal (?) strange stuff
1589 */
1590 case RES_TXTATR_FIELD:
1591 case RES_TXTATR_ANNOTATION:
1592 case RES_TXTATR_INPUTFIELD:
1593 {
1594 SwNodeIndex aIdx(rEntry.m_aMkPos.m_nNode, 1);
1595 SwPaM aPaM(aIdx, rEntry.m_aMkPos.m_nContent);
1596
1597 SwFormatField& rFormatField = *static_cast<SwFormatField*>(rEntry.pAttr.get());
1598 SwField* pField = rFormatField.GetField();
1599
1600 if (!RefToVar(pField, rEntry))
1601 {
1602 sal_uInt16 nBkmNo;
1603 if( IsFootnoteEdnBkmField(rFormatField, nBkmNo) )
1604 {
1605 ::sw::mark::IMark const * const pMark = rDoc.getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo];
1606
1607 const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1608
1609 SwTextNode* pText = rBkMrkPos.nNode.GetNode().GetTextNode();
1610 if( pText && rBkMrkPos.nContent.GetIndex() )
1611 {
1612 SwTextAttr* const pFootnote = pText->GetTextAttrForCharAt(
1613 rBkMrkPos.nContent.GetIndex()-1, RES_TXTATR_FTN );
1614 if( pFootnote )
1615 {
1616 sal_uInt16 nRefNo = static_cast<SwTextFootnote*>(pFootnote)->GetSeqRefNo();
1617
1618 static_cast<SwGetRefField*>(pField)->SetSeqNo( nRefNo );
1619
1620 if( pFootnote->GetFootnote().IsEndNote() )
1621 static_cast<SwGetRefField*>(pField)->SetSubType(REF_ENDNOTE);
1622 }
1623 }
1624 }
1625 }
1626
1627 rDoc.getIDocumentContentOperations().InsertPoolItem(aPaM, *rEntry.pAttr);
1628 MoveAttrs(*aPaM.GetPoint());
1629 }
1630 break;
1631 case RES_FLTR_TOX:
1632 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1633 break;
1634 default:
1635 case RES_FLTR_BOOKMARK:
1636 OSL_ENSURE(false, "EndStck used with non field, not what we want")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1636" ": "), "%s", "EndStck used with non field, not what we want"
); } } while (false)
;
1637 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1638 break;
1639 }
1640}
1641
1642/*
1643 For styles we will do our tabstop arithmetic in word style and adjust them to
1644 writer style after all the styles have been finished and the dust settles as
1645 to what affects what.
1646
1647 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1648 word indexes and we'll turn them back into writer indexes when setting them
1649 into the document. If explicit left indent exist which affects them, then this
1650 is handled when the explicit left indent is set into the document
1651*/
1652void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1653{
1654 if (nLen < 0)
1655 {
1656 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_TABSTOP);
1657 return;
1658 }
1659
1660 sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1661 const sal_uInt8* pDel = pData + 1; // Del - Array
1662
1663 sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1664 const sal_uInt8* pIns = pData + 2*nDel + 2; // Ins - Array
1665
1666 short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1667 if (nRequiredLength > nLen)
1668 {
1669 // would require more data than available to describe!
1670 // discard invalid record
1671 nIns = 0;
1672 nDel = 0;
1673 }
1674
1675 WW8_TBD const * pTyp = reinterpret_cast<WW8_TBD const *>(pData + 2*nDel + 2*nIns + 2); // Type Array
1676
1677 std::shared_ptr<SvxTabStopItem> aAttr(std::make_shared<SvxTabStopItem>(0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP));
1678
1679 const SwFormat * pSty = nullptr;
1680 sal_uInt16 nTabBase;
1681 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // StyleDef
1682 {
1683 nTabBase = m_vColl[m_nCurrentColl].m_nBase;
1684 if (nTabBase < m_vColl.size()) // Based On
1685 pSty = m_vColl[nTabBase].m_pFormat;
1686 }
1687 else
1688 { // Text
1689 nTabBase = m_nCurrentColl;
1690 if (m_nCurrentColl < m_vColl.size())
1691 pSty = m_vColl[m_nCurrentColl].m_pFormat;
1692 //TODO: figure out else here
1693 }
1694
1695 bool bFound = false;
1696 std::unordered_set<size_t> aLoopWatch;
1697 while (pSty && !bFound)
1698 {
1699 const SfxPoolItem* pTabs;
1700 bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1701 &pTabs) == SfxItemState::SET;
1702 if( bFound )
1703 {
1704 aAttr.reset(static_cast<SvxTabStopItem*>(pTabs->Clone()));
1705 }
1706 else
1707 {
1708 sal_uInt16 nOldTabBase = nTabBase;
1709 // If based on another
1710 if (nTabBase < m_vColl.size())
1711 nTabBase = m_vColl[nTabBase].m_nBase;
1712
1713 if (
1714 nTabBase < m_vColl.size() &&
1715 nOldTabBase != nTabBase &&
1716 nTabBase != ww::stiNil
1717 )
1718 {
1719 // #i61789: Stop searching when next style is the same as the
1720 // current one (prevent loop)
1721 aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1722 if (nTabBase < m_vColl.size())
1723 pSty = m_vColl[nTabBase].m_pFormat;
1724 //TODO figure out the else branch
1725
1726 if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1727 aLoopWatch.end())
1728 pSty = nullptr;
1729 }
1730 else
1731 pSty = nullptr; // Give up on the search
1732 }
1733 }
1734
1735 SvxTabStop aTabStop;
1736 for (short i=0; i < nDel; ++i)
1737 {
1738 sal_uInt16 nPos = aAttr->GetPos(SVBT16ToUInt16(pDel + i*2));
1739 if( nPos != SVX_TAB_NOTFOUND(32767 *2 +1) )
1740 aAttr->Remove( nPos );
1741 }
1742
1743 for (short i=0; i < nIns; ++i)
1744 {
1745 short nPos = SVBT16ToUInt16(pIns + i*2);
1746 aTabStop.GetTabPos() = nPos;
1747 switch( pTyp[i].aBits1 & 0x7 ) // pTyp[i].jc
1748 {
1749 case 0:
1750 aTabStop.GetAdjustment() = SvxTabAdjust::Left;
1751 break;
1752 case 1:
1753 aTabStop.GetAdjustment() = SvxTabAdjust::Center;
1754 break;
1755 case 2:
1756 aTabStop.GetAdjustment() = SvxTabAdjust::Right;
1757 break;
1758 case 3:
1759 aTabStop.GetAdjustment() = SvxTabAdjust::Decimal;
1760 break;
1761 case 4:
1762 continue; // Ignore Bar
1763 }
1764
1765 switch( pTyp[i].aBits1 >> 3 & 0x7 )
1766 {
1767 case 0:
1768 aTabStop.GetFill() = ' ';
1769 break;
1770 case 1:
1771 aTabStop.GetFill() = '.';
1772 break;
1773 case 2:
1774 aTabStop.GetFill() = '-';
1775 break;
1776 case 3:
1777 case 4:
1778 aTabStop.GetFill() = '_';
1779 break;
1780 }
1781
1782 sal_uInt16 nPos2 = aAttr->GetPos( nPos );
1783 if (nPos2 != SVX_TAB_NOTFOUND(32767 *2 +1))
1784 aAttr->Remove(nPos2); // Or else Insert() refuses
1785 aAttr->Insert(aTabStop);
1786 }
1787
1788 if (nIns || nDel)
1789 NewAttr(*aAttr);
1790 else
1791 {
1792 // Here we have a tab definition which inserts no extra tabs, or deletes
1793 // no existing tabs. An older version of writer is probably the creator
1794 // of the document :-( . So if we are importing a style we can just
1795 // ignore it. But if we are importing into text we cannot as during
1796 // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1797 // the range the attrib affects, and ignoring it would upset the
1798 // balance
1799 if (!m_pCurrentColl) // not importing into a style
1800 {
1801 SvxTabStopItem aOrig = pSty ?
1802 ItemGet<SvxTabStopItem>(*pSty, RES_PARATR_TABSTOP) :
1803 DefaultItemGet<SvxTabStopItem>(m_rDoc, RES_PARATR_TABSTOP);
1804 NewAttr(aOrig);
1805 }
1806 }
1807}
1808
1809/**
1810 * DOP
1811*/
1812void SwWW8ImplReader::ImportDop()
1813{
1814 // correct the LastPrinted date in DocumentProperties
1815 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1816 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1817 uno::Reference<document::XDocumentProperties> xDocuProps(
1818 xDPS->getDocumentProperties());
1819 OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null")do { if (true && (!(xDocuProps.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "1819" ": "), "%s", "DocumentProperties is null"); } } while
(false)
;
1820 if (xDocuProps.is())
1821 {
1822 DateTime aLastPrinted(
1823 msfilter::util::DTTM2DateTime(m_xWDop->dttmLastPrint));
1824 ::util::DateTime uDT = aLastPrinted.GetUNODateTime();
1825 xDocuProps->setPrintDate(uDT);
1826 }
1827
1828 // COMPATIBILITY FLAGS START
1829
1830 // #i78951# - remember the unknown compatibility options
1831 // so as to export them out
1832 m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1(m_xWDop->GetCompatibilityOptions());
1833 m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2(m_xWDop->GetCompatibilityOptions2());
1834
1835 // The distance between two paragraphs is the sum of the bottom distance of
1836 // the first paragraph and the top distance of the second one
1837 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX, m_xWDop->fDontUseHTMLAutoSpacing);
1838 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, true );
1839 // move tabs on alignment
1840 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT, true);
1841 // #i24363# tab stops relative to indent
1842 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT, false);
1843 // tdf#117923
1844 m_rDoc.getIDocumentSettingAccess().set(
1845 DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING, true);
1846 m_rDoc.getIDocumentSettingAccess().set(
1847 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS, true);
1848 // tdf#128195
1849 m_rDoc.getIDocumentSettingAccess().set(
1850 DocumentSettingId::HEADER_SPACING_BELOW_LAST_PARA, true);
1851 m_rDoc.getIDocumentSettingAccess().set(
1852 DocumentSettingId::FRAME_AUTOWIDTH_WITH_MORE_PARA, true);
1853
1854 // Import Default Tabs
1855 long nDefTabSiz = m_xWDop->dxaTab;
1856 if( nDefTabSiz < 56 )
1857 nDefTabSiz = 709;
1858
1859 // We want exactly one DefaultTab
1860 SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SvxTabAdjust::Default, RES_PARATR_TABSTOP );
1861 const_cast<SvxTabStop&>(aNewTab[0]).GetAdjustment() = SvxTabAdjust::Default;
1862
1863 m_rDoc.GetAttrPool().SetPoolDefaultItem( aNewTab );
1864
1865 // Import zoom factor
1866 if (m_xWDop->wScaleSaved)
1867 {
1868 //Import zoom type
1869 sal_Int16 nZoomType;
1870 switch (m_xWDop->zkSaved) {
1871 case 1: nZoomType = sal_Int16(SvxZoomType::WHOLEPAGE); break;
1872 case 2: nZoomType = sal_Int16(SvxZoomType::PAGEWIDTH); break;
1873 case 3: nZoomType = sal_Int16(SvxZoomType::OPTIMAL); break;
1874 default: nZoomType = sal_Int16(SvxZoomType::PERCENT); break;
1875 }
1876 uno::Sequence<beans::PropertyValue> aViewProps( comphelper::InitPropertySequence({
1877 { "ZoomFactor", uno::Any(sal_Int16(m_xWDop->wScaleSaved)) },
1878 { "VisibleBottom", uno::Any(sal_Int32(0)) },
1879 { "ZoomType", uno::Any(nZoomType) }
1880 }));
1881
1882 uno::Reference< uno::XComponentContext > xComponentContext(comphelper::getProcessComponentContext());
1883 uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(xComponentContext);
1884 xBox->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps));
1885 uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
1886 xViewDataSupplier->setViewData(xBox);
1887 }
1888
1889 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE, !m_xWDop->fUsePrinterMetrics);
1890 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE, true);
1891 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS, true );
1892 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, !m_xWDop->fNoLeading);
1893 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING, false);
1894 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING, false); // #i47448#
1895 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, !m_xWDop->fExpShRtn); // #i49277#, #i56856#
1896 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT, false); // #i53199#
1897 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING, false);
1898
1899 // #i25901# - set new compatibility option
1900 // 'Add paragraph and table spacing at bottom of table cells'
1901 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, true);
1902 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, true);
1903
1904 // #i11860# - set new compatibility option
1905 // 'Use former object positioning' to <false>
1906 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS, false);
1907
1908 // #i27767# - set new compatibility option
1909 // 'Consider Wrapping mode when positioning object' to <true>
1910 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, true);
1911
1912 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, false); // #i13832#, #i24135#
1913
1914 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1915
1916 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, true); // #i3952#
1917
1918 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING, true);
1919 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA, true);
1920 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVERFLOW, true);
1921 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS, true);
1922 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES, true);
1923 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
1924 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL, true);
1925 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE, true);
1926 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
1927
1928 // COMPATIBILITY FLAGS END
1929
1930 // Import magic doptypography information, if its there
1931 if (m_xWwFib->m_nFib > 105)
1932 ImportDopTypography(m_xWDop->doptypography);
1933
1934 // disable form design mode to be able to use imported controls directly
1935 // #i31239# always disable form design mode, not only in protected docs
1936 uno::Reference<beans::XPropertySet> xDocProps(m_pDocShell->GetModel(), uno::UNO_QUERY);
1937 if (xDocProps.is())
1938 {
1939 uno::Reference<beans::XPropertySetInfo> xInfo = xDocProps->getPropertySetInfo();
1940 if (xInfo.is())
1941 {
1942 if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1943 xDocProps->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(false));
1944 }
1945 }
1946
1947 // The password can force read-only, comments-only, fill-in-form-only, or require track-changes.
1948 // Treat comments-only like read-only since Writer has no support for that.
1949 // Still allow editing of form fields, without requiring the password.
1950 // Still allow editing if track-changes is locked on. (Currently LockRev is ignored/lost on export anyway.)
1951 if (!m_xWDop->fProtEnabled && !m_xWDop->fLockRev)
1952 m_pDocShell->SetModifyPasswordHash(m_xWDop->lKeyProtDoc);
1953 else if ( xDocProps.is() )
1954 {
1955 comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
1956 aGrabBag["FormPasswordHash"] <<= m_xWDop->lKeyProtDoc;
1957 xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
1958 }
1959
1960 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
1961 if (rOpt.IsUseEnhancedFields())
1962 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM, m_xWDop->fProtEnabled );
1963}
1964
1965void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography &rTypo)
1966{
1967 switch (rTypo.m_iLevelOfKinsoku)
1968 {
1969 case 2: // custom
1970 {
1971 i18n::ForbiddenCharacters aForbidden(OUString(+rTypo.m_rgxchFPunct),
1972 OUString(+rTypo.m_rgxchLPunct));
1973 // unary + makes sure not to accidentally call the
1974 // OUString(ConstCharArrayDetector<...>::TypeUtf16) ctor that takes the full
1975 // m_rgxchFPunct, m_rgxchLPunct arrays with embedded NULs, instead of just the
1976 // prefix leading up to the first NUL
1977 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(rTypo.GetConvertedLang(),
1978 aForbidden);
1979 // Obviously cannot set the standard level 1 for japanese, so
1980 // bail out now while we can.
1981 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESELanguageType(0x0411))
1982 return;
1983 }
1984 break;
1985 default:
1986 break;
1987 }
1988
1989 /*
1990 This MS hack means that level 2 of japanese is not in operation, so we put
1991 in what we know are the MS defaults, there is a complementary reverse
1992 hack in the writer. Its our default as well, but we can set it anyway
1993 as a flag for later.
1994 */
1995 if (!rTypo.m_reserved2)
1996 {
1997 i18n::ForbiddenCharacters aForbidden(WW8DopTypography::JapanNotBeginLevel1,
1998 WW8DopTypography::JapanNotEndLevel1);
1999 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESELanguageType(0x0411),aForbidden);
2000 }
2001
2002 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION, bool(rTypo.m_fKerningPunct));
2003 m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType>(rTypo.m_iJustification));
2004}
2005
2006/**
2007 * Footnotes and Endnotes
2008 */
2009WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader* pRdr ,WW8_CP nStartCp) :
2010 maTmpPos(*pRdr->m_pPaM->GetPoint()),
2011 mxOldStck(std::move(pRdr->m_xCtrlStck)),
2012 mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
2013 mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
2014 mxOldPlcxMan(pRdr->m_xPlcxMan),
2015 mpWFlyPara(std::move(pRdr->m_xWFlyPara)),
2016 mpSFlyPara(std::move(pRdr->m_xSFlyPara)),
2017 mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
2018 mpPrevNumRule(pRdr->m_pPrevNumRule),
2019 mxTableDesc(std::move(pRdr->m_xTableDesc)),
2020 mnInTable(pRdr->m_nInTable),
2021 mnCurrentColl(pRdr->m_nCurrentColl),
2022 mcSymbol(pRdr->m_cSymbol),
2023 mbIgnoreText(pRdr->m_bIgnoreText),
2024 mbSymbol(pRdr->m_bSymbol),
2025 mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2026 mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2027 mbAnl(pRdr->m_bAnl),
2028 mbInHyperlink(pRdr->m_bInHyperlink),
2029 mbPgSecBreak(pRdr->m_bPgSecBreak),
2030 mbWasParaEnd(pRdr->m_bWasParaEnd),
2031 mbHasBorder(pRdr->m_bHasBorder),
2032 mbFirstPara(pRdr->m_bFirstPara)
2033{
2034 pRdr->m_bSymbol = false;
2035 pRdr->m_bHdFtFootnoteEdn = true;
2036 pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2037 = pRdr->m_bHasBorder = false;
2038 pRdr->m_bFirstPara = true;
2039 pRdr->m_nInTable = 0;
2040 pRdr->m_pPreviousNumPaM = nullptr;
2041 pRdr->m_pPrevNumRule = nullptr;
2042 pRdr->m_nCurrentColl = 0;
2043
2044 pRdr->m_xCtrlStck.reset(new SwWW8FltControlStack(pRdr->m_rDoc, pRdr->m_nFieldFlags,
2045 *pRdr));
2046
2047 pRdr->m_xRedlineStack.reset(new sw::util::RedlineStack(pRdr->m_rDoc));
2048
2049 pRdr->m_xAnchorStck.reset(new SwWW8FltAnchorStack(pRdr->m_rDoc, pRdr->m_nFieldFlags));
2050
2051 // Save the attribute manager: we need this as the newly created PLCFx Manager
2052 // access the same FKPs as the old one and their Start-End position changes.
2053 if (pRdr->m_xPlcxMan)
2054 pRdr->m_xPlcxMan->SaveAllPLCFx(maPLCFxSave);
2055
2056 if (nStartCp != -1)
2057 {
2058 pRdr->m_xPlcxMan = std::make_shared<WW8PLCFMan>(pRdr->m_xSBase.get(),
2059 mxOldPlcxMan->GetManType(), nStartCp);
2060 }
2061
2062 maOldApos.push_back(false);
2063 maOldApos.swap(pRdr->m_aApos);
2064 maOldFieldStack.swap(pRdr->m_aFieldStack);
2065}
2066
2067void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
2068{
2069 pRdr->m_xWFlyPara = std::move(mpWFlyPara);
2070 pRdr->m_xSFlyPara = std::move(mpSFlyPara);
2071 pRdr->m_pPreviousNumPaM = mpPreviousNumPaM;
2072 pRdr->m_pPrevNumRule = mpPrevNumRule;
2073 pRdr->m_xTableDesc = std::move(mxTableDesc);
2074 pRdr->m_cSymbol = mcSymbol;
2075 pRdr->m_bSymbol = mbSymbol;
2076 pRdr->m_bIgnoreText = mbIgnoreText;
2077 pRdr->m_bHdFtFootnoteEdn = mbHdFtFootnoteEdn;
2078 pRdr->m_bTxbxFlySection = mbTxbxFlySection;
2079 pRdr->m_nInTable = mnInTable;
2080 pRdr->m_bAnl = mbAnl;
2081 pRdr->m_bInHyperlink = mbInHyperlink;
2082 pRdr->m_bWasParaEnd = mbWasParaEnd;
2083 pRdr->m_bPgSecBreak = mbPgSecBreak;
2084 pRdr->m_nCurrentColl = mnCurrentColl;
2085 pRdr->m_bHasBorder = mbHasBorder;
2086 pRdr->m_bFirstPara = mbFirstPara;
2087
2088 // Close all attributes as attributes could be created that extend the Fly
2089 pRdr->DeleteCtrlStack();
2090 pRdr->m_xCtrlStck = std::move(mxOldStck);
2091
2092 pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2093 pRdr->m_aFrameRedlines.emplace(std::move(pRdr->m_xRedlineStack));
2094 pRdr->m_xRedlineStack = std::move(mxOldRedlines);
2095
2096 pRdr->DeleteAnchorStack();
2097 pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
2098
2099 *pRdr->m_pPaM->GetPoint() = maTmpPos;
2100
2101 if (mxOldPlcxMan != pRdr->m_xPlcxMan)
2102 pRdr->m_xPlcxMan = mxOldPlcxMan;
2103 if (pRdr->m_xPlcxMan)
2104 pRdr->m_xPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2105 pRdr->m_aApos.swap(maOldApos);
2106 pRdr->m_aFieldStack.swap(maOldFieldStack);
2107}
2108
2109void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex* pSttIdx,
2110 WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2111{
2112 if (nStartCp < 0 || nLen < 0)
2113 return;
2114
2115 // Saves Flags (amongst other things) and resets them
2116 WW8ReaderSave aSave( this );
2117
2118 m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2119 m_pPaM->GetPoint()->nContent.Assign( m_pPaM->GetContentNode(), 0 );
2120
2121 // Read Text for Header, Footer or Footnote
2122 ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2123 aSave.Restore( this );
2124}
2125
2126/**
2127 * Use authornames, if not available fall back to initials.
2128 */
2129long SwWW8ImplReader::Read_And(WW8PLCFManResult* pRes)
2130{
2131 WW8PLCFx_SubDoc* pSD = m_xPlcxMan->GetAtn();
2132 if (!pSD)
2133 return 0;
2134
2135 const void* pData = pSD->GetData();
2136 if (!pData)
2137 return 0;
2138
2139 OUString sAuthor;
2140 OUString sInitials;
2141 if( m_bVer67 )
2142 {
2143 const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2144 const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst));
2145 if (pA)
2146 sAuthor = *pA;
2147 else
2148 {
2149 const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2150 SAL_N_ELEMENTS(pDescri->xstUsrInitl)(sizeof(sal_n_array_size(pDescri->xstUsrInitl)))-1);
2151 sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1)));
2152 }
2153 }
2154 else
2155 {
2156 const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2157 {
2158 const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToUInt16(pDescri->xstUsrInitl[0]),
2159 SAL_N_ELEMENTS(pDescri->xstUsrInitl)(sizeof(sal_n_array_size(pDescri->xstUsrInitl)))-1);
2160 OUStringBuffer aBuf;
2161 aBuf.setLength(nLen);
2162 for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2163 aBuf[nIdx-1] = SVBT16ToUInt16(pDescri->xstUsrInitl[nIdx]);
2164 sInitials = aBuf.makeStringAndClear();
2165 }
2166
2167 if (const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst)))
2168 sAuthor = *pA;
2169 else
2170 sAuthor = sInitials;
2171 }
2172
2173 sal_uInt32 nDateTime = 0;
2174
2175 if (sal_uInt8 * pExtended = m_xPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2176 {
2177 sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2178 if (m_xWwFib->m_lcbAtrdExtra/18 > nIndex)
2179 nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2180 }
2181
2182 DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2183
2184 OUString sText;
2185 std::unique_ptr<OutlinerParaObject> pOutliner = ImportAsOutliner( sText, pRes->nCp2OrIdx,
2186 pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2187
2188 m_pFormatOfJustInsertedApo = nullptr;
2189 SwPostItField aPostIt(
2190 static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), sAuthor,
2191 sText, sInitials, OUString(), aDate );
2192 aPostIt.SetTextObject(std::move(pOutliner));
2193
2194 SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2195 m_xCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2196 m_rDoc.getIDocumentContentOperations().InsertPoolItem(aEnd, SwFormatField(aPostIt));
2197 m_xCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2198 // If this is a range, make sure that it ends after the just inserted character, not before it.
2199 m_xReffedStck->MoveAttrs(*aEnd.GetPoint(), SwFltControlStack::MoveAttrsMode::POSTIT_INSERTED);
2200
2201 return 0;
2202}
2203
2204void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart, WW8_CP nLen,
2205 SwFrameFormat const &rHdFtFormat, sal_uInt16 nPageWidth)
2206{
2207 const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2208 OSL_ENSURE(pSttIdx, "impossible")do { if (true && (!(pSttIdx))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2208" ": "), "%s", "impossible"); } } while (false)
;
2209 if (!pSttIdx)
2210 return;
2211
2212 SwPosition aTmpPos(*m_pPaM->GetPoint());
2213
2214 m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2215 m_pPaM->GetPoint()->nContent.Assign(m_pPaM->GetContentNode(), 0);
2216
2217 // tdf#122425: Explicitly remove borders and spacing
2218 SfxItemSet aFlySet(m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END - 1>{});
2219 Reader::ResetFrameFormatAttrs(aFlySet);
2220
2221 SwFlyFrameFormat* pFrame
2222 = m_rDoc.MakeFlySection(RndStdIds::FLY_AT_PARA, m_pPaM->GetPoint(), &aFlySet);
2223
2224 SwFormatAnchor aAnch( pFrame->GetAnchor() );
2225 aAnch.SetType( RndStdIds::FLY_AT_PARA );
2226 pFrame->SetFormatAttr( aAnch );
2227 SwFormatFrameSize aSz(SwFrameSize::Minimum, nPageWidth, MINLAY23);
2228 SwFrameSize eFrameSize = SwFrameSize::Minimum;
2229 if( eFrameSize != aSz.GetWidthSizeType() )
2230 aSz.SetWidthSizeType( eFrameSize );
2231 pFrame->SetFormatAttr(aSz);
2232 pFrame->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH));
2233 pFrame->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
2234
2235 // #i43427# - send frame for header/footer into background.
2236 pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2237 SdrObject* pFrameObj = CreateContactObject( pFrame );
2238 OSL_ENSURE( pFrameObj,do { if (true && (!(pFrameObj))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2239" ": "), "%s", "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance"
); } } while (false)
2239 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" )do { if (true && (!(pFrameObj))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2239" ": "), "%s", "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance"
); } } while (false)
;
2240 if ( pFrameObj )
2241 {
2242 pFrameObj->SetOrdNum( 0 );
2243 }
2244 MoveInsideFly(pFrame);
2245
2246 const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2247
2248 Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2249
2250 MoveOutsideFly(pFrame, aTmpPos);
2251}
2252
2253void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat const * pHdFtFormat)
2254{
2255 const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2256 if (!pSttIdx)
2257 return;
2258
2259 SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2260
2261 Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2262
2263 *m_pPaM->GetPoint() = aTmpPos;
2264}
2265
2266bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP) const
2267{
2268 // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2269 return (nHeaderCP < m_xWwFib->m_ccpHdr && nHeaderCP >= 0);
2270}
2271
2272bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems, sal_uInt8 grpfIhdt,
2273 int nSect)
2274{
2275 if (m_xHdFt)
2276 {
2277 WW8_CP nStart, nLen;
2278 sal_uInt8 nNumber = 5;
2279
2280 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2281 {
2282 if (nI & nWhichItems)
2283 {
2284 bool bOk = true;
2285 if( m_bVer67 )
2286 bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2287 else
2288 {
2289 m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2290 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2291 }
2292
2293 if (bOk)
2294 return true;
2295 }
2296 }
2297 }
2298 return false;
2299}
2300
2301void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2302 const wwSection &rSection)
2303{
2304 sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2305 SwPageDesc *pPD = rSection.mpPage;
2306
2307 if( !m_xHdFt )
2308 return;
2309
2310 WW8_CP nStart, nLen;
2311 sal_uInt8 nNumber = 5;
2312
2313 // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2314 // corresponding to bit fields in grpfIhdt indicating which
2315 // header/footer(s) are present in this section
2316 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2317 {
2318 if (nI & grpfIhdt)
2319 {
2320 bool bOk = true;
2321 if( m_bVer67 )
2322 bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2323 else
2324 {
2325 m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2326 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2327 }
2328
2329 bool bUseLeft
2330 = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2331 bool bUseFirst
2332 = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2333
2334 // If we are loading a first-page header/footer which is not
2335 // actually enabled in this section (it still needs to be
2336 // loaded as it may be inherited by a later section)
2337 bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2338
2339 bool bFooter
2340 = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2341
2342 SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2343 : bUseFirst ? pPD->GetFirstMaster()
2344 : pPD->GetMaster();
2345
2346 SwFrameFormat* pHdFtFormat;
2347 // If we have empty first page header and footer.
2348 bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2349 if (bFooter)
2350 {
2351 m_bIsFooter = true;
2352 //#i17196# Cannot have left without right
2353 if (!bDisabledFirst
2354 && !pPD->GetMaster().GetFooter().GetFooterFormat())
2355 pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2356 if (bUseLeft)
2357 pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2358 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2359 pPD->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2360 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2361 }
2362 else
2363 {
2364 m_bIsHeader = true;
2365 //#i17196# Cannot have left without right
2366 if (!bDisabledFirst
2367 && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2368 pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2369 if (bUseLeft)
2370 pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2371 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2372 pPD->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2373 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2374 }
2375
2376 if (bOk)
2377 {
2378 bool bHackRequired = false;
2379 if (m_bIsHeader && rSection.IsFixedHeightHeader())
2380 bHackRequired = true;
2381 else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2382 bHackRequired = true;
2383
2384 if (bHackRequired)
2385 {
2386 Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2387 static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2388 }
2389 else
2390 Read_HdFtText(nStart, nLen, pHdFtFormat);
2391 }
2392 else if (pPrev)
2393 CopyPageDescHdFt(pPrev, pPD, nI);
2394
2395 m_bIsHeader = m_bIsFooter = false;
2396 }
2397 }
2398}
2399
2400bool wwSectionManager::SectionIsProtected(const wwSection &rSection) const
2401{
2402 return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() );
2403}
2404
2405void wwSectionManager::SetHdFt(wwSection const &rSection, int nSect,
2406 const wwSection *pPrevious)
2407{
2408 // Header/Footer not present
2409 if (!rSection.maSep.grpfIhdt)
2410 return;
2411
2412 OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page")do { if (true && (!(rSection.mpPage))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2412" ": "), "%s", "makes no sense to call with a main page"
); } } while (false)
;
2413 if (rSection.mpPage)
2414 {
2415 mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2416 rSection);
2417 }
2418
2419 // Header/Footer - Update Index
2420 // So that the index is still valid later on
2421 if (mrReader.m_xHdFt)
2422 mrReader.m_xHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2423
2424}
2425
2426void SwWW8ImplReader::AppendTextNode(SwPosition& rPos)
2427{
2428 SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
2429
2430 const SwNumRule* pRule = nullptr;
2431
2432 if (pText != nullptr)
2433 pRule = sw::util::GetNumRuleFromTextNode(*pText);
2434
2435 if (
2436 pRule && !m_xWDop->fDontUseHTMLAutoSpacing &&
2437 (m_bParaAutoBefore || m_bParaAutoAfter)
2438 )
2439 {
2440 // If after spacing is set to auto, set the after space to 0
2441 if (m_bParaAutoAfter)
2442 SetLowerSpacing(*m_pPaM, 0);
2443
2444 // If the previous textnode had numbering and
2445 // and before spacing is set to auto, set before space to 0
2446 if(m_pPrevNumRule && m_bParaAutoBefore)
2447 SetUpperSpacing(*m_pPaM, 0);
2448
2449 // If the previous numbering rule was different we need
2450 // to insert a space after the previous paragraph
2451 if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2452 SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2453
2454 // cache current paragraph
2455 if(m_pPreviousNumPaM)
2456 {
2457 delete m_pPreviousNumPaM;
2458 m_pPreviousNumPaM = nullptr;
2459 }
2460
2461 m_pPreviousNumPaM = new SwPaM(*m_pPaM, m_pPaM);
2462 m_pPrevNumRule = pRule;
2463 }
2464 else if(!pRule && m_pPreviousNumPaM)
2465 {
2466 // If the previous paragraph has numbering but the current one does not
2467 // we need to add a space after the previous paragraph
2468 SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2469 delete m_pPreviousNumPaM;
2470 m_pPreviousNumPaM = nullptr;
2471 m_pPrevNumRule = nullptr;
2472 }
2473 else
2474 {
2475 // clear paragraph cache
2476 if(m_pPreviousNumPaM)
2477 {
2478 delete m_pPreviousNumPaM;
2479 m_pPreviousNumPaM = nullptr;
2480 }
2481 m_pPrevNumRule = pRule;
2482 }
2483
2484 // If this is the first paragraph in the document and
2485 // Auto-spacing before paragraph is set,
2486 // set the upper spacing value to 0
2487 if(m_bParaAutoBefore && m_bFirstPara && !m_xWDop->fDontUseHTMLAutoSpacing)
2488 SetUpperSpacing(*m_pPaM, 0);
2489
2490 m_bFirstPara = false;
2491
2492 m_rDoc.getIDocumentContentOperations().AppendTextNode(rPos);
2493
2494 // We can flush all anchored graphics at the end of a paragraph.
2495 m_xAnchorStck->Flush();
2496}
2497
2498bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2499{
2500 bool bRet = false;
2501 const SwPosition* pSpacingPos = rMyPam.GetPoint();
2502
2503 const SvxULSpaceItem* pULSpaceItem = m_xCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE);
2504
2505 if(pULSpaceItem != nullptr)
2506 {
2507 SvxULSpaceItem aUL(*pULSpaceItem);
2508
2509 if(bIsUpper)
2510 aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2511 else
2512 aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2513
2514 const sal_Int32 nEnd = pSpacingPos->nContent.GetIndex();
2515 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), 0);
2516 m_xCtrlStck->NewAttr(*pSpacingPos, aUL);
2517 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), nEnd);
2518 m_xCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2519 bRet = true;
2520 }
2521 return bRet;
2522}
2523
2524bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2525{
2526 return SetSpacing(rMyPam, nSpace, false);
2527}
2528
2529bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2530{
2531 return SetSpacing(rMyPam, nSpace, true);
2532}
2533
2534sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2535{
2536 if (m_bVer67)
2537 return NS_sprm::v6::sprmPTtp;
2538 return nLevel ? NS_sprm::PFInnerTtp::val : NS_sprm::PFTtp::val;
2539}
2540
2541void SwWW8ImplReader::EndSpecial()
2542{
2543 // Frame/Table/Anl
2544 if (m_bAnl)
2545 StopAllAnl(); // -> bAnl = false
2546
2547 while(m_aApos.size() > 1)
2548 {
2549 StopTable();
2550 m_aApos.pop_back();
2551 --m_nInTable;
2552 if (m_aApos[m_nInTable])
2553 StopApo();
2554 }
2555
2556 if (m_aApos[0])
2557 StopApo();
2558
2559 OSL_ENSURE(!m_nInTable, "unclosed table!")do { if (true && (!(!m_nInTable))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2559" ": "), "%s", "unclosed table!"); } } while (false
)
;
2560}
2561
2562bool SwWW8ImplReader::FloatingTableConversion(WW8PLCFx_Cp_FKP* pPap)
2563{
2564 // This is ww8 version of the code deciding if the table needs to be
2565 // in a floating frame.
2566 // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2567 // writerfilter/source/dmapper/PropertyMap.cxx
2568 // The two should do ~same, so if you make changes here, please check
2569 // that the other is in sync.
2570
2571 // Note that this is just a list of heuristics till sw core can have a
2572 // table that is floating and can span over multiple pages at the same
2573 // time.
2574
2575 // If the floating table is in a header or footer, then it won't be a
2576 // multi-page one, so can always do the conversion.
2577 if (m_bIsHeader || m_bIsFooter)
2578 {
2579 return true;
2580 }
2581
2582 bool bResult = true;
2583
2584 SprmResult aRes = pPap->HasSprm(NS_sprm::TDefTable::val);
2585 if (nullptr != aRes.pSprm)
2586 {
2587 bResult = false;
2588 WW8TabBandDesc aDesc;
2589 aDesc.ReadDef(false, aRes.pSprm, aRes.nRemainingData);
2590 int nTextAreaWidth = m_aSectionManager.GetTextAreaWidth();
2591 int nTableWidth = aDesc.nCenter[aDesc.nWwCols] - aDesc.nCenter[0];
2592
2593 // It seems Word has a limit here, so that in case the table width is quite
2594 // close to the text area width, then it won't perform a wrapping, even in
2595 // case the content (e.g. an empty paragraph) would fit. The magic constant
2596 // here represents this limit.
2597 const int nMagicNumber = 469;
2598
2599 // If the table is wider than the text area, then don't create a fly
2600 // for the table: no wrapping will be performed anyway, but multi-page
2601 // tables will be broken.
2602 if ((nTableWidth + nMagicNumber) < nTextAreaWidth)
2603 bResult = true;
2604
2605 // If there are columns, do create a fly, as the flow of the columns
2606 // would otherwise restrict the table.
2607 if (!bResult && (m_aSectionManager.CurrentSectionColCount() >= 2))
2608 bResult = true;
2609 }
2610
2611 if (bResult)
2612 {
2613 WW8PLCFxSave1 aSave;
2614 pPap->Save(aSave);
2615 if (SearchTableEnd(pPap))
2616 {
2617 // Table is considered to be imported into a fly frame and we
2618 // know where the end of the table is.
2619 bool bIsUnicode;
2620 WW8_FC nFc = m_xSBase->WW8Cp2Fc(pPap->Where(), &bIsUnicode);
2621 sal_uInt64 nPos = m_pStrm->Tell();
2622 m_pStrm->Seek(nFc);
2623 sal_uInt16 nUChar = 0;
2624 if (bIsUnicode)
2625 m_pStrm->ReadUInt16(nUChar);
2626 else
2627 {
2628 sal_uInt8 nChar = 0;
2629 m_pStrm->ReadUChar(nChar);
2630 nUChar = nChar;
2631 }
2632 m_pStrm->Seek(nPos);
2633 if (nUChar == 0xc)
2634 // The pap after the table starts with a page break, so
2635 // there will be no wrapping around the float-table.
2636 // Request no fly in this case, so the table can properly
2637 // be a multi-page one if necessary.
2638 bResult = false;
2639 }
2640 pPap->Restore(aSave);
2641 }
2642
2643 return bResult;
2644}
2645
2646bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2647{
2648 // Frame/Table/Anl
2649 if (m_bInHyperlink)
2650 return false;
2651
2652 rbReSync = false;
2653
2654 OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!")do { if (true && (!(m_nInTable >= 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2654" ": "), "%s", "nInTable < 0!"); } } while (false
)
;
2655
2656 // TabRowEnd
2657 bool bTableRowEnd = (m_xPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417).pSprm != nullptr);
2658
2659// Unfortunately, for every paragraph we need to check first whether
2660// they contain a sprm 29 (0x261B), which starts an APO.
2661// All other sprms then refer to that APO and not to the normal text
2662// surrounding it.
2663// The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2664
2665// WW: Table in APO is possible (Both Start-Ends occur at the same time)
2666// WW: APO in Table not possible
2667
2668// This mean that of a Table is the content of an APO, the APO start needs
2669// to be edited first, so that the Table remains in the APO and not the
2670// other way around.
2671// At the End, however, we need to edit the Table End first as the APO
2672// must end after that Table (or else we never find the APO End).
2673
2674// The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2675
2676// If the Table is within an APO the TabRowEnd Area misses the
2677// APO settings.
2678// To not end the APO there, we do not call ProcessApo
2679
2680// KHZ: When there is a table inside the Apo the Apo-flags are also
2681// missing for the 2nd, 3rd... paragraphs of each cell.
2682
2683// 1st look for in-table flag, for 2000+ there is a subtable flag to
2684// be considered, the sprm 6649 gives the level of the table
2685 sal_uInt8 nCellLevel = 0;
2686
2687 if (m_bVer67)
2688 nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(24).pSprm);
2689 else
2690 {
2691 nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x2416).pSprm);
2692 if (!nCellLevel)
2693 nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x244B).pSprm);
2694 }
2695 do
2696 {
2697 WW8_TablePos *pTabPos=nullptr;
2698 WW8_TablePos aTabPos;
2699 if(nCellLevel && !m_bVer67)
2700 {
2701 WW8PLCFxSave1 aSave;
2702 m_xPlcxMan->GetPap()->Save( aSave );
2703 rbReSync = true;
2704 WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
2705 WW8_CP nMyStartCp=nStartCp;
2706
2707 SprmResult aLevel = m_xPlcxMan->HasParaSprm(0x6649);
2708 if (aLevel.pSprm && aLevel.nRemainingData >= 1)
2709 nCellLevel = *aLevel.pSprm;
2710
2711 bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2712
2713 // Bad Table, remain unchanged in level, e.g. #i19667#
2714 if (!bHasRowEnd)
2715 nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2716
2717 if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2718 pTabPos = &aTabPos;
2719
2720 m_xPlcxMan->GetPap()->Restore( aSave );
2721 }
2722
2723 // Then look if we are in an Apo
2724
2725 ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2726
2727 // Look to see if we are in a Table, but Table in foot/end note not allowed
2728 bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2729
2730 bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2731
2732 m_bWasTabRowEnd = false; // must be deactivated right here to prevent next
2733 // WW8TabDesc::TableCellEnd() from making nonsense
2734
2735 if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2736 bStopTab = bStartTab = true; // Required to stop and start table
2737
2738 // Test for Anl (Numbering) and process all events in the right order
2739 if( m_bAnl && !bTableRowEnd )
2740 {
2741 SprmResult aSprm13 = m_xPlcxMan->HasParaSprm(13);
2742 const sal_uInt8* pSprm13 = aSprm13.pSprm;
2743 if (pSprm13 && aSprm13.nRemainingData >= 1)
2744 { // Still Anl left?
2745 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2746 if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2747 || aApo.HasStartStop() // Forced Anl end
2748 || bStopTab || bStartTab )
2749 {
2750 StopAnlToRestart(nT); // Anl-Restart (= change) over sprms
2751 }
2752 else
2753 {
2754 NextAnlLine( pSprm13 ); // Next Anl Line
2755 }
2756 }
2757 else
2758 { // Regular Anl end
2759 StopAllAnl(); // Actual end
2760 }
2761 }
2762 if (bStopTab)
2763 {
2764 StopTable();
2765 m_aApos.pop_back();
2766 --m_nInTable;
2767 }
2768 if (aApo.mbStopApo)
2769 {
2770 StopApo();
2771 m_aApos[m_nInTable] = false;
2772 }
2773
2774 if (aApo.mbStartApo)
2775 {
2776 m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2777 // We need an ReSync after StartApo
2778 // (actually only if the Apo extends past a FKP border)
2779 rbReSync = true;
2780 }
2781 if (bStartTab)
2782 {
2783 WW8PLCFxSave1 aSave;
2784 m_xPlcxMan->GetPap()->Save( aSave );
2785
2786 // Numbering for cell borders causes a crash -> no Anls in Tables
2787 if (m_bAnl)
2788 StopAllAnl();
2789
2790 if(m_nInTable < nCellLevel)
2791 {
2792 if (StartTable(nStartCp))
2793 ++m_nInTable;
2794 else
2795 break;
2796 m_aApos.push_back(false);
2797 }
2798
2799 if(m_nInTable >= nCellLevel)
2800 {
2801 // We need an ReSync after StartTable
2802 // (actually only if the Apo extends past a FKP border)
2803 rbReSync = true;
2804 m_xPlcxMan->GetPap()->Restore( aSave );
2805 }
2806 }
2807 } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2808 return bTableRowEnd;
2809}
2810
2811rtl_TextEncoding SwWW8ImplReader::GetCharSetFromLanguage()
2812{
2813 /*
2814 #i22206#/#i52786#
2815 The (default) character set used for a run of text is the default
2816 character set for the version of Word that last saved the document.
2817
2818 This is a bit tentative, more might be required if the concept is correct.
2819 When later version of word write older 6/95 documents the charset is
2820 correctly set in the character runs involved, so it's hard to reproduce
2821 documents that require this to be sure of the process involved.
2822 */
2823 const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_LANGUAGE));
2824 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEMLanguageType(0x0000);
2825 css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2826 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2827}
2828
2829rtl_TextEncoding SwWW8ImplReader::GetCJKCharSetFromLanguage()
2830{
2831 /*
2832 #i22206#/#i52786#
2833 The (default) character set used for a run of text is the default
2834 character set for the version of Word that last saved the document.
2835
2836 This is a bit tentative, more might be required if the concept is correct.
2837 When later version of word write older 6/95 documents the charset is
2838 correctly set in the character runs involved, so it's hard to reproduce
2839 documents that require this to be sure of the process involved.
2840 */
2841 const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE));
2842 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEMLanguageType(0x0000);
2843 css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2844 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2845}
2846
2847rtl_TextEncoding SwWW8ImplReader::GetCurrentCharSet()
2848{
2849 /*
2850 #i2015
2851 If the hard charset is set use it, if not see if there is an open
2852 character run that has set the charset, if not then fallback to the
2853 current underlying paragraph style.
2854 */
2855 rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2856 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)))
2857 {
2858 if (!m_bVer67)
2859 eSrcCharSet = GetCharSetFromLanguage();
2860 else if (!m_aFontSrcCharSets.empty())
2861 eSrcCharSet = m_aFontSrcCharSets.top();
2862 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0))) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2863 eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2864 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0))) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2865 eSrcCharSet = m_vColl[m_nCurrentColl].GetCharSet();
2866 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)))
2867 eSrcCharSet = GetCharSetFromLanguage();
2868 }
2869 return eSrcCharSet;
2870}
2871
2872//Takashi Ono for CJK
2873rtl_TextEncoding SwWW8ImplReader::GetCurrentCJKCharSet()
2874{
2875 /*
2876 #i2015
2877 If the hard charset is set use it, if not see if there is an open
2878 character run that has set the charset, if not then fallback to the
2879 current underlying paragraph style.
2880 */
2881 rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2882 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)))
2883 {
2884 if (!m_aFontSrcCJKCharSets.empty())
2885 eSrcCharSet = m_aFontSrcCJKCharSets.top();
2886 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0))) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2887 eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2888 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2889 eSrcCharSet = m_vColl[m_nCurrentColl].GetCJKCharSet();
2890 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)))
2891 eSrcCharSet = GetCJKCharSetFromLanguage();
2892 }
2893 return eSrcCharSet;
2894}
2895
2896void SwWW8ImplReader::PostProcessAttrs()
2897{
2898 if (m_pPostProcessAttrsInfo == nullptr)
2899 return;
2900
2901 SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2902
2903 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2904 {
2905 m_xCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2906 *pItem);
2907 m_xCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2908 pItem->Which());
2909 }
2910
2911 m_pPostProcessAttrsInfo.reset();
2912}
2913
2914/*
2915 #i9240#
2916 It appears that some documents that are in a baltic 8 bit encoding which has
2917 some undefined characters can have use made of those characters, in which
2918 case they default to CP1252. If not then it's perhaps that the font encoding
2919 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2920 is always 1252.
2921
2922 So an encoding converter that on an undefined character attempts to
2923 convert from 1252 on the undefined character
2924*/
2925static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2926 char const *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2927{
2928 const sal_uInt32 nFlags =
2929 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001) |
2930 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR((sal_uInt32)0x0010) |
2931 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE((sal_uInt32)0x0200) |
2932 RTL_TEXTTOUNICODE_FLAGS_FLUSH((sal_uInt32)0x8000);
2933
2934 const sal_uInt32 nFlags2 =
2935 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE((sal_uInt32)0x0002) |
2936 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE((sal_uInt32)0x0020) |
2937 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE((sal_uInt32)0x0200) |
2938 RTL_TEXTTOUNICODE_FLAGS_FLUSH((sal_uInt32)0x8000);
2939
2940 std::size_t nDestChars=0;
2941 std::size_t nConverted=0;
2942
2943 do
2944 {
2945 sal_uInt32 nInfo = 0;
2946 sal_Size nThisConverted=0;
2947
2948 nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2949 pIn+nConverted, nInLen-nConverted,
2950 pOut+nDestChars, nOutLen-nDestChars,
2951 nFlags, &nInfo, &nThisConverted);
2952
2953 OSL_ENSURE(nInfo == 0, "A character conversion failed!")do { if (true && (!(nInfo == 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "2953" ": "), "%s", "A character conversion failed!"); }
} while (false)
;
2954
2955 nConverted += nThisConverted;
2956
2957 if (
2958 nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED((sal_uInt32)0x0008) ||
2959 nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED((sal_uInt32)0x0010)
2960 )
2961 {
2962 sal_Size nOtherConverted;
2963 rtl_TextToUnicodeConverter hCP1252Converter =
2964 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1)));
2965 nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2966 pIn+nConverted, 1,
2967 pOut+nDestChars, nOutLen-nDestChars,
2968 nFlags2, &nInfo, &nOtherConverted);
2969 rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2970 nConverted+=1;
2971 }
2972 } while (nConverted < nInLen);
2973
2974 return nDestChars;
2975}
2976
2977bool SwWW8ImplReader::LangUsesHindiNumbers(LanguageType nLang)
2978{
2979 bool bResult = false;
2980
2981 switch (static_cast<sal_uInt16>(nLang))
2982 {
2983 case 0x1401: // Arabic(Algeria)
2984 case 0x3c01: // Arabic(Bahrain)
2985 case 0xc01: // Arabic(Egypt)
2986 case 0x801: // Arabic(Iraq)
2987 case 0x2c01: // Arabic (Jordan)
2988 case 0x3401: // Arabic(Kuwait)
2989 case 0x3001: // Arabic(Lebanon)
2990 case 0x1001: // Arabic(Libya)
2991 case 0x1801: // Arabic(Morocco)
2992 case 0x2001: // Arabic(Oman)
2993 case 0x4001: // Arabic(Qatar)
2994 case 0x401: // Arabic(Saudi Arabia)
2995 case 0x2801: // Arabic(Syria)
2996 case 0x1c01: // Arabic(Tunisia)
2997 case 0x3801: // Arabic(U.A.E)
2998 case 0x2401: // Arabic(Yemen)
2999 bResult = true;
3000 break;
3001 default:
3002 break;
3003 }
3004
3005 return bResult;
3006}
3007
3008sal_Unicode SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar)
3009{
3010 if (nChar >= 0x0030 && nChar <= 0x0039)
3011 return nChar + 0x0630;
3012
3013 return nChar;
3014}
3015
3016namespace
3017{
3018 OUString makeOUString(rtl_uString *pStr, sal_Int32 nAllocLen)
3019 {
3020 //if read len was in or around that of allocated len, just reuse pStr
3021 if (nAllocLen < pStr->length + 256)
3022 return OUString(pStr, SAL_NO_ACQUIRE);
3023 //otherwise copy the shorter used section to release extra mem
3024 OUString sRet(pStr->buffer, pStr->length);
3025 rtl_uString_release(pStr);
3026 return sRet;
3027 }
3028}
3029
3030/**
3031 * Return value: true for non special chars
3032 */
3033bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3034{
3035 sal_Int32 nRequestedStrLen = nEnd - rPos;
3036
3037 OSL_ENSURE(nRequestedStrLen, "String is 0")do { if (true && (!(nRequestedStrLen))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3037" ": "), "%s", "String is 0"); } } while (false)
;
3038 if (nRequestedStrLen <= 0)
3039 return true;
3040
3041 sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+rPos, &m_bIsUnicode);
3042 bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3043 OSL_ENSURE(bValidPos, "Document claimed to have more text than available")do { if (true && (!(bValidPos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3043" ": "), "%s", "Document claimed to have more text than available"
); } } while (false)
;
3044 if (!bValidPos)
3045 {
3046 // Swallow missing range, e.g. #i95550#
3047 rPos+=nRequestedStrLen;
3048 return true;
3049 }
3050
3051 std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3052 OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available")do { if (true && (!(nAvailableStrLen))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3052" ": "), "%s", "Document claimed to have more text than available"
); } } while (false)
;
3053 if (!nAvailableStrLen)
3054 {
3055 // Swallow missing range, e.g. #i95550#
3056 rPos+=nRequestedStrLen;
3057 return true;
3058 }
3059
3060 sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3061
3062 // Reset Unicode flag and correct FilePos if needed.
3063 // Note: Seek is not expensive, as we're checking inline whether or not
3064 // the correct FilePos has already been reached.
3065 const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF)-1);
3066
3067 rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3068 RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1));
3069 if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932(((rtl_TextEncoding) 60)))
3070 {
3071 /*
3072 fdo#82904
3073
3074 Older documents exported as word 95 that use unicode aware fonts will
3075 have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3076 export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3077 pain.
3078
3079 We will try and use a fallback encoding if the conversion from
3080 RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3081 which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3082 valid RTL_TEXTENCODING_MS_932 by chance :-(
3083
3084 We're not the only ones that struggle with this: Here's the help from
3085 MSOffice 2003 on the topic:
3086
3087 <<
3088 Earlier versions of Microsoft Word were sometimes used in conjunction with
3089 third-party language-processing add-in programs designed to support Chinese or
3090 Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3091 results in incorrect text display in more recent versions of Word.
3092
3093 However, you can set options to convert these documents so that text is
3094 displayed correctly. On the Tools menu, click Options, and then click the
3095 General tab. In the English Word 6.0/95 documents list, select Contain Asian
3096 text (to have Word interpret the text as Asian code page data, regardless of
3097 its font) or Automatically detect Asian text (to have Word attempt to determine
3098 which parts of the text are meant to be Asian).
3099 >>
3100
3101 What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3102 the language is not Japanese
3103 */
3104
3105 const SfxPoolItem * pItem = GetFormatAttr(RES_CHRATR_CJK_LANGUAGE);
3106 if (pItem != nullptr && LANGUAGE_JAPANESELanguageType(0x0411) != static_cast<const SvxLanguageItem *>(pItem)->GetLanguage())
3107 {
3108 SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "discarding word95 RTL_TEXTENCODING_MS_932 encoding"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3108" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "discarding word95 RTL_TEXTENCODING_MS_932 encoding"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "discarding word95 RTL_TEXTENCODING_MS_932 encoding"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3108" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "discarding word95 RTL_TEXTENCODING_MS_932 encoding"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3108" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "discarding word95 RTL_TEXTENCODING_MS_932 encoding"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "discarding word95 RTL_TEXTENCODING_MS_932 encoding"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3108" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3109 eSrcCharSet = GetCharSetFromLanguage();
3110 }
3111 }
3112 const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3113 RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1));
3114
3115 // allocate unicode string data
3116 rtl_uString *pStr = rtl_uString_alloc(nStrLen);
3117 sal_Unicode* pBuffer = pStr->buffer;
3118 sal_Unicode* pWork = pBuffer;
3119
3120 std::unique_ptr<char[]> p8Bits;
3121
3122 rtl_TextToUnicodeConverter hConverter = nullptr;
3123 if (!m_bIsUnicode || m_bVer67)
3124 hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3125
3126 if (!m_bIsUnicode)
3127 p8Bits.reset( new char[nStrLen] );
3128
3129 // read the stream data
3130 sal_uInt8 nBCode = 0;
3131 sal_uInt16 nUCode;
3132
3133 LanguageType nCTLLang = LANGUAGE_SYSTEMLanguageType(0x0000);
3134 const SfxPoolItem * pItem = GetFormatAttr(RES_CHRATR_CTL_LANGUAGE);
3135 if (pItem != nullptr)
3136 nCTLLang = static_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
3137
3138 sal_Int32 nL2;
3139 for (nL2 = 0; nL2 < nStrLen; ++nL2)
3140 {
3141 if (m_bIsUnicode)
3142 m_pStrm->ReadUInt16( nUCode ); // unicode --> read 2 bytes
3143 else
3144 {
3145 m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3146 nUCode = nBCode;
3147 }
3148
3149 if (m_pStrm->GetError())
3150 {
3151 rPos = WW8_CP_MAX-10; // -> eof or other error
3152 std::free(pStr);
3153 return true;
3154 }
3155
3156 if ((32 > nUCode) || (0xa0 == nUCode))
3157 {
3158 m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3159 break; // Special character < 32, == 0xa0 found
3160 }
3161
3162 if (m_bIsUnicode)
3163 {
3164 if (!m_bVer67)
3165 *pWork++ = nUCode;
3166 else
3167 {
3168 if (nUCode >= 0x3000) //0x8000 ?
3169 {
3170 char aTest[2];
3171 aTest[0] = static_cast< char >((nUCode & 0xFF00) >> 8);
3172 aTest[1] = static_cast< char >(nUCode & 0x00FF);
3173 OUString aTemp(aTest, 2, eSrcCJKCharSet);
3174 OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory")do { if (true && (!(aTemp.getLength() == 1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3174" ": "), "%s", "so much for that theory"); } } while
(false)
;
3175 *pWork++ = aTemp[0];
3176 }
3177 else
3178 {
3179 char cTest = static_cast< char >(nUCode & 0x00FF);
3180 pWork += Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3181 }
3182 }
3183 }
3184 else
3185 p8Bits[nL2] = nBCode;
3186 }
3187
3188 if (nL2)
3189 {
3190 const sal_Int32 nEndUsed = !m_bIsUnicode
3191 ? Custom8BitToUnicode(hConverter, p8Bits.get(), nL2, pBuffer, nStrLen)
3192 : pWork - pBuffer;
3193
3194 if (m_bRegardHindiDigits && m_bBidi && LangUsesHindiNumbers(nCTLLang))
3195 {
3196 for (sal_Int32 nI = 0; nI < nEndUsed; ++nI, ++pBuffer)
3197 *pBuffer = TranslateToHindiNumbers(*pBuffer);
3198 }
3199
3200 pStr->buffer[nEndUsed] = 0;
3201 pStr->length = nEndUsed;
3202
3203 emulateMSWordAddTextToParagraph(makeOUString(pStr, nStrLen));
3204 pStr = nullptr;
3205 rPos += nL2;
3206 if (!m_aApos.back()) // a para end in apo doesn't count
3207 m_bWasParaEnd = false; // No CR
3208 }
3209
3210 if (hConverter)
3211 rtl_destroyTextToUnicodeConverter(hConverter);
3212 if (pStr)
3213 rtl_uString_release(pStr);
3214 return nL2 >= nStrLen;
3215}
3216
3217#define MSASCII((sal_Int16) 0x7FFF) SAL_MAX_INT16((sal_Int16) 0x7FFF)
3218
3219namespace
3220{
3221 // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3222 sal_Int16 lcl_getScriptType(
3223 const uno::Reference<i18n::XBreakIterator>& rBI,
3224 const OUString &rString, sal_Int32 nPos)
3225 {
3226 sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3227 if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3228 nScript = MSASCII((sal_Int16) 0x7FFF);
3229 return nScript;
3230 }
3231
3232 // We want to know about WEAK segments, so endOfScript isn't
3233 // useful, and see lcl_getScriptType anyway
3234 sal_Int32 lcl_endOfScript(
3235 const uno::Reference<i18n::XBreakIterator>& rBI,
3236 const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3237 {
3238 while (nPos < rString.getLength())
3239 {
3240 sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3241 if (nScript != nNewScript)
3242 break;
3243 ++nPos;
3244 }
3245 return nPos;
3246 }
3247
3248 sal_Int32 lcl_getWriterScriptType(
3249 const uno::Reference<i18n::XBreakIterator>& rBI,
3250 const OUString &rString, sal_Int32 nPos)
3251 {
3252 sal_Int16 nScript = i18n::ScriptType::WEAK;
3253
3254 if (rString.isEmpty())
3255 return nScript;
3256
3257 while (nPos >= 0)
3258 {
3259 nScript = rBI->getScriptType(rString, nPos);
3260 if (nScript != i18n::ScriptType::WEAK)
3261 break;
3262 --nPos;
3263 }
3264
3265 return nScript;
3266 }
3267
3268 bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3269 {
3270 return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3271 }
3272
3273 bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3274 {
3275 // Ignoring CharSet, and ignoring unknown pitch
3276 return rA.GetFamilyName() == rB.GetFamilyName() &&
3277 rA.GetStyleName() == rB.GetStyleName() &&
3278 rA.GetFamily() == rB.GetFamily() &&
3279 samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3280 }
3281}
3282
3283// In writer we categorize text into CJK, CTL and "Western" for everything else.
3284// Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3285// NonEastAsian/HighAnsi, with some shared characters and some properties to
3286// hint as to which way to bias those shared characters.
3287
3288// That's four categories, we however have three categories. Given that problem
3289// here we would ideally find out "what would word do" to see what font/language
3290// word would assign to characters based on the unicode range they fall into and
3291// hack the word one onto the range we use. However it's unclear what word's
3292// categorization is. So we don't do that here yet.
3293
3294// Additional to the categorization, when word encounters weak text for ambiguous
3295// chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3296// feature in writer.
3297
3298// So what we currently do here then is to split our text into non-weak/weak
3299// sections and uses word's idcthint to determine what font it would use and
3300// force that on for the segment. Following what we *do* know about word's
3301// categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3302// word, something we map to LATIN, so we consider all weak chars in that range
3303// to auto-bias to LATIN.
3304
3305// See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3306void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString& rAddString)
3307{
3308 if (rAddString.isEmpty())
3309 return;
3310
3311 uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3312 assert(xBI.is())(static_cast <bool> (xBI.is()) ? void (0) : __assert_fail
("xBI.is()", "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
, 3312, __extension__ __PRETTY_FUNCTION__))
;
3313
3314 sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3315 sal_Int32 nLen = rAddString.getLength();
3316
3317 OUString sParagraphText;
3318 const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3319 const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3320 if (pNd)
3321 sParagraphText = pNd->GetText();
3322 sal_Int32 nParaOffset = sParagraphText.getLength();
3323 sParagraphText = sParagraphText + rAddString;
3324
3325 sal_Int32 nPos = 0;
3326 while (nPos < nLen)
3327 {
3328 sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3329 if (nEnd < 0)
3330 break;
3331
3332 OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3333 const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3334 const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3335 bool aForced[] = {false, false, false};
3336
3337 int nLclIdctHint = 0xFF;
3338 if (nScript == i18n::ScriptType::WEAK)
3339 {
3340 const SfxInt16Item *pIdctHint = static_cast<const SfxInt16Item*>(GetFormatAttr(RES_CHRATR_IDCTHINT));
3341 nLclIdctHint = pIdctHint->GetValue();
3342 }
3343 else if (nScript == MSASCII((sal_Int16) 0x7FFF)) // Force weak chars in ascii range to use LATIN font
3344 nLclIdctHint = 0;
3345
3346 sal_uInt16 nForceFromFontId = 0;
3347 if (nLclIdctHint != 0xFF)
3348 {
3349 switch (nLclIdctHint)
3350 {
3351 case 0:
3352 nForceFromFontId = RES_CHRATR_FONT;
3353 break;
3354 case 1:
3355 nForceFromFontId = RES_CHRATR_CJK_FONT;
3356 break;
3357 case 2:
3358 nForceFromFontId = RES_CHRATR_CTL_FONT;
3359 break;
3360 default:
3361 break;
3362 }
3363 }
3364
3365 if (nForceFromFontId != 0)
3366 {
3367 // Now we know that word would use the nForceFromFontId font for this range
3368 // Try and determine what script writer would assign this range to
3369
3370 sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3371 nPos + nParaOffset);
3372
3373 bool bWriterWillUseSameFontAsWordAutomatically = false;
3374
3375 if (nWriterScript != i18n::ScriptType::WEAK)
3376 {
3377 if (
3378 (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3379 (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3380 (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3381 )
3382 {
3383 bWriterWillUseSameFontAsWordAutomatically = true;
3384 }
3385 else
3386 {
3387 const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3388 sal_uInt16 nDestId = aIds[nWriterScript-1];
3389 const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(nDestId));
3390 bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3391 }
3392 }
3393
3394 // Writer won't use the same font as word, so force the issue
3395 if (!bWriterWillUseSameFontAsWordAutomatically)
3396 {
3397 const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3398
3399 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds)(sizeof(sal_n_array_size(aIds))); ++i)
3400 {
3401 const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(aIds[i]));
3402 aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3403 if (aForced[i])
3404 {
3405 pOverriddenItems[i] =
3406 static_cast<const SvxFontItem*>(m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3407
3408 SvxFontItem aForceFont(*pSourceFont);
3409 aForceFont.SetWhich(aIds[i]);
3410 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3411 }
3412 }
3413 }
3414 }
3415
3416 simpleAddTextToParagraph(sChunk);
3417
3418 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds)(sizeof(sal_n_array_size(aIds))); ++i)
3419 {
3420 if (aForced[i])
3421 {
3422 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3423 if (pOverriddenItems[i])
3424 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3425 }
3426 }
3427
3428 nPos = nEnd;
3429 if (nPos < nLen)
3430 nScript = lcl_getScriptType(xBI, rAddString, nPos);
3431 }
3432}
3433
3434namespace sw {
3435
3436auto FilterControlChars(OUString const& rString) -> OUString
3437{
3438 OUStringBuffer buf(rString.getLength());
3439 for (sal_Int32 i = 0; i < rString.getLength(); ++i)
3440 {
3441 sal_Unicode const ch(rString[i]);
3442 if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
3443 {
3444 buf.append(ch);
3445 }
3446 else
3447 {
3448 SAL_INFO("sw.ww8", "filtering control character")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "filtering control character"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3448" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "filtering control character"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "filtering control character"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3448" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "filtering control character") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3448" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "filtering control character"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "filtering control character"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3448" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3449 }
3450 }
3451 return buf.makeStringAndClear();
3452}
3453
3454} // namespace sw
3455
3456void SwWW8ImplReader::simpleAddTextToParagraph(const OUString& rAddString)
3457{
3458 OUString const addString(sw::FilterControlChars(rAddString));
3459
3460 if (addString.isEmpty())
3461 return;
3462
3463#if OSL_DEBUG_LEVEL1 > 1
3464 SAL_INFO("sw.ww8", "<addTextToParagraph>" << addString << "</addTextToParagraph>")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "<addTextToParagraph>"
<< addString << "</addTextToParagraph>") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3464" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "<addTextToParagraph>" <<
addString << "</addTextToParagraph>"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"<addTextToParagraph>" << addString << "</addTextToParagraph>"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3464" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "<addTextToParagraph>" << addString <<
"</addTextToParagraph>") == 1) { ::sal_detail_log( (::
SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3464" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "<addTextToParagraph>" <<
addString << "</addTextToParagraph>"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"<addTextToParagraph>" << addString << "</addTextToParagraph>"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3464" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3465#endif
3466
3467 const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3468 const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3469
3470 OSL_ENSURE(pNd, "What the hell, where's my text node")do { if (true && (!(pNd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3470" ": "), "%s", "What the hell, where's my text node"
); } } while (false)
;
3471
3472 if (!pNd)
3473 return;
3474
3475 const sal_Int32 nCharsLeft = SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF) - pNd->GetText().getLength();
3476 if (nCharsLeft > 0)
3477 {
3478 if (addString.getLength() <= nCharsLeft)
3479 {
3480 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString);
3481 }
3482 else
3483 {
3484 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(0, nCharsLeft));
3485 AppendTextNode(*m_pPaM->GetPoint());
3486 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(nCharsLeft));
3487 }
3488 }
3489 else
3490 {
3491 AppendTextNode(*m_pPaM->GetPoint());
3492 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString);
3493 }
3494
3495 m_bReadTable = false;
3496}
3497
3498/**
3499 * Return value: true for para end
3500 */
3501bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, long nTextEnd,
3502 long nCpOfs)
3503{
3504 long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3505
3506 if (m_bSymbol || m_bIgnoreText)
3507 {
3508 WW8_CP nRequested = nEnd - rPos;
3509 if (m_bSymbol) // Insert special chars
3510 {
3511 sal_uInt64 nMaxPossible = m_pStrm->remainingSize();
3512 if (o3tl::make_unsigned(nRequested) > nMaxPossible)
3513 {
3514 SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested << " than remaining, " << nMaxPossible)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "document claims to have more characters, "
<< nRequested << " than remaining, " << nMaxPossible
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3514" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "document claims to have more characters, "
<< nRequested << " than remaining, " << nMaxPossible
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "document claims to have more characters, " <<
nRequested << " than remaining, " << nMaxPossible
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3514" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "document claims to have more characters, " <<
nRequested << " than remaining, " << nMaxPossible
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3514" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "document claims to have more characters, "
<< nRequested << " than remaining, " << nMaxPossible
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "document claims to have more characters, " <<
nRequested << " than remaining, " << nMaxPossible
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3514" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3515 nRequested = nMaxPossible;
3516 }
3517
3518 if (!linguistic::IsControlChar(m_cSymbol)
3519 || m_cSymbol == '\r' || m_cSymbol == '\n' || m_cSymbol == '\t')
3520 {
3521 for (WW8_CP nCh = 0; nCh < nRequested; ++nCh)
3522 {
3523 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, OUString(m_cSymbol));
3524 }
3525 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_FONT);
3526 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_CJK_FONT);
3527 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_CTL_FONT);
3528 }
3529 }
3530 m_pStrm->SeekRel(nRequested);
3531 rPos = nEnd; // Ignore until attribute end
3532 return false;
3533 }
3534
3535 while (true)
3536 {
3537 if (ReadPlainChars(rPos, nEnd, nCpOfs))
3538 return false; // Done
3539
3540 bool bStartLine = ReadChar(rPos, nCpOfs);
3541 rPos++;
3542 if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3543 {
3544 return bStartLine;
3545 }
3546 }
3547}
3548
3549bool SwWW8ImplReader::HandlePageBreakChar()
3550{
3551 bool bParaEndAdded = false;
3552 // #i1909# section/page breaks should not occur in tables, word
3553 // itself ignores them in this case.
3554 if (!m_nInTable)
3555 {
3556 bool IsTemp=true;
3557 SwTextNode* pTemp = m_pPaM->GetNode().GetTextNode();
3558 if (pTemp && pTemp->GetText().isEmpty()
3559 && (m_bFirstPara || m_bFirstParaOfPage))
3560 {
3561 IsTemp = false;
3562 AppendTextNode(*m_pPaM->GetPoint());
3563 pTemp->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE));
3564 }
3565
3566 m_bPgSecBreak = true;
3567 m_xCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3568 /*
3569 If it's a 0x0c without a paragraph end before it, act like a
3570 paragraph end, but nevertheless, numbering (and perhaps other
3571 similar constructs) do not exist on the para.
3572 */
3573 if (!m_bWasParaEnd && IsTemp)
3574 {
3575 bParaEndAdded = true;
3576 if (0 >= m_pPaM->GetPoint()->nContent.GetIndex())
3577 {
3578 if (SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode())
3579 {
3580 pTextNode->SetAttr(
3581 *GetDfltAttr(RES_PARATR_NUMRULE));
3582 }
3583 }
3584 }
3585 }
3586 return bParaEndAdded;
3587}
3588
3589bool SwWW8ImplReader::ReadChar(long nPosCp, long nCpOfs)
3590{
3591 bool bNewParaEnd = false;
3592 // Reset Unicode flag and correct FilePos if needed.
3593 // Note: Seek is not expensive, as we're checking inline whether or not
3594 // the correct FilePos has already been reached.
3595 std::size_t nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3596 if (!checkSeek(*m_pStrm, nRequestedPos))
3597 return false;
3598
3599 sal_uInt16 nWCharVal(0);
3600 if( m_bIsUnicode )
3601 m_pStrm->ReadUInt16( nWCharVal ); // unicode --> read 2 bytes
3602 else
3603 {
3604 sal_uInt8 nBCode(0);
3605 m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3606 nWCharVal = nBCode;
3607 }
3608
3609 sal_Unicode cInsert = '\x0';
3610 bool bParaMark = false;
3611
3612 if ( 0xc != nWCharVal )
3613 m_bFirstParaOfPage = false;
3614
3615 switch (nWCharVal)
3616 {
3617 case 0:
3618 {
3619 // Page number
3620 SwPageNumberField aField(
3621 static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3622 SwFieldIds::PageNumber )), PG_RANDOM, SVX_NUM_ARABIC);
3623 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SwFormatField(aField));
3624 }
3625 break;
3626 case 0xe:
3627 // if there is only one column word treats a column break like a pagebreak.
3628 if (m_aSectionManager.CurrentSectionColCount() < 2)
3629 bParaMark = HandlePageBreakChar();
3630 else if (!m_nInTable)
3631 {
3632 // Always insert a txtnode for a column break, e.g. ##
3633 SwContentNode *pCntNd=m_pPaM->GetContentNode();
3634 if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3635 AppendTextNode(*m_pPaM->GetPoint());
3636 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
3637 }
3638 break;
3639 case 0x7:
3640 {
3641 bNewParaEnd = true;
3642 WW8PLCFxDesc* pPap = m_xPlcxMan->GetPap();
3643 //The last paragraph of each cell is terminated by a special
3644 //paragraph mark called a cell mark. Following the cell mark
3645 //that ends the last cell of a table row, the table row is
3646 //terminated by a special paragraph mark called a row mark
3647 //
3648 //So the 0x7 should be right at the end of the previous
3649 //range to be a real cell-end.
3650 if (pPap->nOrigStartPos == nPosCp+1 ||
3651 pPap->nOrigStartPos == WW8_CP_MAX)
3652 {
3653 TabCellEnd(); // Table cell/row end
3654 }
3655 else
3656 bParaMark = true;
3657 }
3658 break;
3659 case 0xf:
3660 if( !m_bSpec ) // "Satellite"
3661 cInsert = u'\x00a4';
3662 break;
3663 case 0x14:
3664 if( !m_bSpec ) // "Para End" char
3665 cInsert = u'\x00b5';
3666 //TODO: should this be U+00B6 PILCROW SIGN rather than
3667 // U+00B5 MICRO SIGN?
3668 break;
3669 case 0x15:
3670 if( !m_bSpec ) // Juristenparagraph
3671 {
3672 cp_set::iterator aItr = m_aTOXEndCps.find(static_cast<WW8_CP>(nPosCp));
3673 if (aItr == m_aTOXEndCps.end())
3674 cInsert = u'\x00a7';
3675 else
3676 m_aTOXEndCps.erase(aItr);
3677 }
3678 break;
3679 case 0x9:
3680 cInsert = '\x9'; // Tab
3681 break;
3682 case 0xb:
3683 cInsert = '\xa'; // Hard NewLine
3684 break;
3685 case 0xc:
3686 bParaMark = HandlePageBreakChar();
3687 break;
3688 case 0x1e: // Non-breaking hyphen
3689 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDHYPHENu'\x2011') );
3690 break;
3691 case 0x1f: // Non-required hyphens
3692 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_SOFTHYPHENu'\x00AD') );
3693 break;
3694 case 0xa0: // Non-breaking spaces
3695 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDBLANKu'\x00A0') );
3696 break;
3697 case 0x1:
3698 /*
3699 Current thinking is that if bObj is set then we have a
3700 straightforward "traditional" ole object, otherwise we have a
3701 graphic preview of an associated ole2 object (or a simple
3702 graphic of course)
3703
3704 normally in the canvas field, the code is 0x8 0x1.
3705 in a special case, the code is 0x1 0x1, which yields a simple picture
3706 */
3707 {
3708 bool bReadObj = IsInlineEscherHack();
3709 if( bReadObj )
3710 {
3711 long nCurPos = m_pStrm->Tell();
3712 sal_uInt16 nWordCode(0);
3713
3714 if( m_bIsUnicode )
3715 m_pStrm->ReadUInt16( nWordCode );
3716 else
3717 {
3718 sal_uInt8 nByteCode(0);
3719 m_pStrm->ReadUChar( nByteCode );
3720 nWordCode = nByteCode;
3721 }
3722 if( nWordCode == 0x1 )
3723 bReadObj = false;
3724 m_pStrm->Seek( nCurPos );
3725 }
3726 if( !bReadObj )
3727 {
3728 SwFrameFormat *pResult = nullptr;
3729 if (m_bObj)
3730 pResult = ImportOle();
3731 else if (m_bSpec)
3732 pResult = ImportGraf();
3733
3734 // If we have a bad 0x1 insert a space instead.
3735 if (!pResult)
3736 {
3737 cInsert = ' ';
3738 OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,do { if (true && (!(!m_bObj && !m_bEmbeddObj &&
!m_nObjLocFc))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3740" ": "), "%s", "WW8: Please report this document, it may have a "
"missing graphic"); } } while (false)
3739 "WW8: Please report this document, it may have a "do { if (true && (!(!m_bObj && !m_bEmbeddObj &&
!m_nObjLocFc))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3740" ": "), "%s", "WW8: Please report this document, it may have a "
"missing graphic"); } } while (false)
3740 "missing graphic")do { if (true && (!(!m_bObj && !m_bEmbeddObj &&
!m_nObjLocFc))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3740" ": "), "%s", "WW8: Please report this document, it may have a "
"missing graphic"); } } while (false)
;
3741 }
3742 else
3743 {
3744 // reset the flags.
3745 m_bObj = m_bEmbeddObj = false;
3746 m_nObjLocFc = 0;
3747 }
3748 }
3749 }
3750 break;
3751 case 0x8:
3752 if( !m_bObj )
3753 Read_GrafLayer( nPosCp );
3754 break;
3755 case 0xd:
3756 bNewParaEnd = bParaMark = true;
3757 if (m_nInTable > 1)
3758 {
3759 /*
3760 #i9666#/#i23161#
3761 Yes complex, if there is an entry in the undocumented PLCF
3762 which I believe to be a record of cell and row boundaries
3763 see if the magic bit which I believe to mean cell end is
3764 set. I also think btw that the third byte of the 4 byte
3765 value is the level of the cell
3766 */
3767 WW8PLCFspecial* pTest = m_xPlcxMan->GetMagicTables();
3768 if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3769 pTest->Where() == nPosCp+1+nCpOfs)
3770 {
3771 WW8_FC nPos;
3772 void *pData;
3773 sal_uInt32 nData = pTest->Get(nPos, pData) ? SVBT32ToUInt32(*static_cast<SVBT32*>(pData))
3774 : 0;
3775 if (nData & 0x2) // Might be how it works
3776 {
3777 TabCellEnd();
3778 bParaMark = false;
3779 }
3780 }
3781 // tdf#106799: We expect TTP marks to be also cell marks,
3782 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3783 else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3784 {
3785 TabCellEnd();
3786 bParaMark = false;
3787 }
3788 }
3789
3790 m_bWasTabCellEnd = false;
3791
3792 break; // line end
3793 case 0x5: // Annotation reference
3794 case 0x13:
3795 break;
3796 case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3797 if (!m_aFootnoteStack.empty())
3798 cInsert = '?';
3799 break;
3800 default:
3801 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.ww8.level2")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "<unknownValue val=\""
<< nWCharVal << "\">") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.ww8.level2"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3801" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "<unknownValue val=\"" << nWCharVal
<< "\">"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "<unknownValue val=\"" <<
nWCharVal << "\">"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8.level2"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3801" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "<unknownValue val=\"" << nWCharVal <<
"\">") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8.level2"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3801" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "<unknownValue val=\"" << nWCharVal
<< "\">"), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "<unknownValue val=\"" <<
nWCharVal << "\">"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.ww8.level2"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3801" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3802 break;
3803 }
3804
3805 if( '\x0' != cInsert )
3806 {
3807 OUString sInsert(cInsert);
3808 emulateMSWordAddTextToParagraph(sInsert);
3809 }
3810 if (!m_aApos.back()) // a para end in apo doesn't count
3811 m_bWasParaEnd = bNewParaEnd;
3812 return bParaMark;
3813}
3814
3815void SwWW8ImplReader::ProcessCurrentCollChange(WW8PLCFManResult& rRes,
3816 bool* pStartAttr, bool bCallProcessSpecial)
3817{
3818 sal_uInt16 nOldColl = m_nCurrentColl;
3819 m_nCurrentColl = m_xPlcxMan->GetColl();
3820
3821 // Invalid Style-Id
3822 if (m_nCurrentColl >= m_vColl.size() || !m_vColl[m_nCurrentColl].m_pFormat || !m_vColl[m_nCurrentColl].m_bColl)
3823 {
3824 m_nCurrentColl = 0;
3825 m_bParaAutoBefore = false;
3826 m_bParaAutoAfter = false;
3827 }
3828 else
3829 {
3830 m_bParaAutoBefore = m_vColl[m_nCurrentColl].m_bParaAutoBefore;
3831 m_bParaAutoAfter = m_vColl[m_nCurrentColl].m_bParaAutoAfter;
3832 }
3833
3834 if (nOldColl >= m_vColl.size())
3835 nOldColl = 0; // guess! TODO make sure this is what we want
3836
3837 bool bTabRowEnd = false;
3838 if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3839 {
3840 bool bReSync;
3841 // Frame/Table/Autonumbering List Level
3842 bTabRowEnd = ProcessSpecial(bReSync, rRes.nCurrentCp + m_xPlcxMan->GetCpOfs());
3843 if( bReSync )
3844 *pStartAttr = m_xPlcxMan->Get( &rRes ); // Get Attribut-Pos again
3845 }
3846
3847 if (!bTabRowEnd && StyleExists(m_nCurrentColl))
3848 {
3849 SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[ m_nCurrentColl ]);
3850 ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nCurrentColl ].m_n81Flags);
3851 ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3852 m_vColl[m_nCurrentColl].m_n81BiDiFlags);
3853 }
3854}
3855
3856long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, long nTextEnd, bool& rbStartLine, int nDepthGuard)
3857{
3858 long nSkipChars = 0;
3859 WW8PLCFManResult aRes;
3860
3861 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode")do { if (true && (!(m_pPaM->GetNode().GetTextNode(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3861" ": "), "%s", "Missing txtnode"); } } while (false
)
;
3862 bool bStartAttr = m_xPlcxMan->Get(&aRes); // Get Attribute position again
3863 aRes.nCurrentCp = rTextPos; // Current Cp position
3864
3865 bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3866 if ( bNewSection ) // New Section
3867 {
3868 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode")do { if (true && (!(m_pPaM->GetNode().GetTextNode(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3868" ": "), "%s", "Missing txtnode"); } } while (false
)
;
3869 // Create PageDesc and fill it
3870 m_aSectionManager.CreateSep(rTextPos);
3871 // -> 0xc was a Sectionbreak, but not a Pagebreak;
3872 // Create PageDesc and fill it
3873 m_bPgSecBreak = false;
3874 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode")do { if (true && (!(m_pPaM->GetNode().GetTextNode(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3874" ": "), "%s", "Missing txtnode"); } } while (false
)
;
3875 }
3876
3877 // New paragraph over Plcx.Fkp.papx
3878 if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3879 {
3880 ProcessCurrentCollChange( aRes, &bStartAttr,
3881 MAN_MASK_NEW_PAP == (aRes.nFlags & MAN_MASK_NEW_PAP) &&
3882 !m_bIgnoreText );
3883 rbStartLine = false;
3884 }
3885
3886 // position of last CP that's to be ignored
3887 long nSkipPos = -1;
3888
3889 if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3890 {
3891 if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3892 {
3893 if( bStartAttr ) // WW attributes
3894 {
3895 if( aRes.nMemLen >= 0 )
3896 ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3897 }
3898 else
3899 EndSprm( aRes.nSprmId ); // Switch off Attr
3900 }
3901 else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3902 {
3903 if (bStartAttr)
3904 {
3905 nSkipChars = ImportExtSprm(&aRes);
3906 if (
3907 (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3908 (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3909 )
3910 {
3911 WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3912 // Skip Field/Footnote-/End-Note here
3913 rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3914 nSkipPos = rTextPos-1;
3915 }
3916 }
3917 else
3918 EndExtSprm( aRes.nSprmId );
3919 }
3920 }
3921
3922 sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(m_xPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3923 bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3924 SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region")do { if (true && (!bValidPos)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Document claimed to have text at an invalid position, skip attributes for region"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3924" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Document claimed to have text at an invalid position, skip attributes for region"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Document claimed to have text at an invalid position, skip attributes for region"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3924" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Document claimed to have text at an invalid position, skip attributes for region"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3924" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Document claimed to have text at an invalid position, skip attributes for region"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Document claimed to have text at an invalid position, skip attributes for region"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3924" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3925
3926 // Find next Attr position (and Skip attributes of field contents if needed)
3927 if (nSkipChars && !m_bIgnoreText)
3928 m_xCtrlStck->MarkAllAttrsOld();
3929 bool bOldIgnoreText = m_bIgnoreText;
3930 m_bIgnoreText = true;
3931 sal_uInt16 nOldColl = m_nCurrentColl;
3932 bool bDoPlcxManPlusPLus = true;
3933 long nNext;
3934 do
3935 {
3936 if( bDoPlcxManPlusPLus )
3937 m_xPlcxMan->advance();
3938 nNext = bValidPos ? m_xPlcxMan->Where() : nTextEnd;
3939
3940 if (m_pPostProcessAttrsInfo &&
3941 m_pPostProcessAttrsInfo->mnCpStart == nNext)
3942 {
3943 m_pPostProcessAttrsInfo->mbCopy = true;
3944 }
3945
3946 if( (0 <= nNext) && (nSkipPos >= nNext) )
3947 {
3948 if (nDepthGuard >= 1024)
3949 {
3950 SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "ReadTextAttr hit recursion limit"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3950" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ReadTextAttr hit recursion limit"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ReadTextAttr hit recursion limit"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3950" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ReadTextAttr hit recursion limit") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3950" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ReadTextAttr hit recursion limit"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ReadTextAttr hit recursion limit"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "3950" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3951 nNext = nTextEnd;
3952 }
3953 else
3954 nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine, nDepthGuard + 1);
3955 bDoPlcxManPlusPLus = false;
3956 m_bIgnoreText = true;
3957 }
3958
3959 if (m_pPostProcessAttrsInfo &&
3960 nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3961 {
3962 m_pPostProcessAttrsInfo->mbCopy = false;
3963 }
3964 }
3965 while( nSkipPos >= nNext );
3966 m_bIgnoreText = bOldIgnoreText;
3967 if( nSkipChars )
3968 {
3969 m_xCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3970 if( nOldColl != m_xPlcxMan->GetColl() )
3971 ProcessCurrentCollChange(aRes, nullptr, false);
3972 }
3973
3974 return nNext;
3975}
3976
3977//Revised 2012.8.16 for the complex attribute presentation of 0x0D in MS
3978bool SwWW8ImplReader::IsParaEndInCPs(sal_Int32 nStart, sal_Int32 nEnd,bool bSdOD) const
3979{
3980 //Revised for performance consideration
3981 if (nStart == -1 || nEnd == -1 || nEnd < nStart )
3982 return false;
3983
3984 return std::any_of(m_aEndParaPos.rbegin(), m_aEndParaPos.rend(),
3985 [=](const WW8_CP& rPos) {
3986 //Revised 2012.8.16,to the 0x0D,the attribute will have two situations
3987 //*********within***********exact******
3988 //*********but also sample with only left and the position of 0x0d is the edge of the right side***********
3989 return (bSdOD && ((nStart < rPos && nEnd > rPos) || (nStart == nEnd && rPos == nStart))) ||
3990 (!bSdOD && (nStart < rPos && nEnd >= rPos));
3991 }
3992 );
3993}
3994
3995//Clear the para end position recorded in reader intermittently for the least impact on loading performance
3996void SwWW8ImplReader::ClearParaEndPosition()
3997{
3998 if ( !m_aEndParaPos.empty() )
3999 m_aEndParaPos.clear();
4000}
4001
4002void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, long nTextEnd, bool& rbStartLine)
4003{
4004 // Do we have attributes?
4005 if( rTextPos >= rNext )
4006 {
4007 do
4008 {
4009 m_aCurrAttrCP = rTextPos;
4010 rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
4011 if (rTextPos == rNext && rTextPos >= nTextEnd)
4012 break;
4013 }
4014 while( rTextPos >= rNext );
4015
4016 }
4017 else if ( rbStartLine )
4018 {
4019 /* No attributes, but still a new line.
4020 * If a line ends with a line break and paragraph attributes or paragraph templates
4021 * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
4022 * is false.
4023 * Due to this we need to set the template here as a kind of special treatment.
4024 */
4025 if (!m_bCpxStyle && m_nCurrentColl < m_vColl.size())
4026 SetTextFormatCollAndListLevel(*m_pPaM, m_vColl[m_nCurrentColl]);
4027 rbStartLine = false;
4028 }
4029}
4030
4031/**
4032 * CloseAttrEnds to only read the attribute ends at the end of a text or a
4033 * text area (Header, Footnote, ...).
4034 * We ignore attribute starts and fields.
4035 */
4036void SwWW8ImplReader::CloseAttrEnds()
4037{
4038 // If there are any unclosed sprms then copy them to
4039 // another stack and close the ones that must be closed
4040 std::stack<sal_uInt16> aStack;
4041 m_xPlcxMan->TransferOpenSprms(aStack);
4042
4043 while (!aStack.empty())
4044 {
4045 sal_uInt16 nSprmId = aStack.top();
4046 if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
4047 EndSprm(nSprmId);
4048 aStack.pop();
4049 }
4050
4051 EndSpecial();
4052}
4053
4054bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4055{
4056 bool bJoined=false;
4057
4058 bool bStartLine = true;
4059 short nCrCount = 0;
4060 short nDistance = 0;
4061
4062 m_bWasParaEnd = false;
4063 m_nCurrentColl = 0;
4064 m_xCurrentItemSet.reset();
4065 m_nCharFormat = -1;
4066 m_bSpec = false;
4067 m_bPgSecBreak = false;
4068
4069 m_xPlcxMan = std::make_shared<WW8PLCFMan>(m_xSBase.get(), nType, nStartCp);
4070 long nCpOfs = m_xPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4071
4072 WW8_CP nNext = m_xPlcxMan->Where();
4073 m_pPreviousNode = nullptr;
4074 sal_uInt8 nDropLines = 0;
4075 SwCharFormat* pNewSwCharFormat = nullptr;
4076 const SwCharFormat* pFormat = nullptr;
4077
4078 bool bValidPos = checkSeek(*m_pStrm, m_xSBase->WW8Cp2Fc(nStartCp + nCpOfs, &m_bIsUnicode));
4079 if (!bValidPos)
4080 return false;
4081
4082 WW8_CP l = nStartCp;
4083 const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4084 if (nTextLen > nMaxPossible)
4085 {
4086 SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long")do { if (true && (nTextLen > nMaxPossible)) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "sw.ww8"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "TextLen too long") == 1) { ::sal_detail_log( (::
SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4086" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TextLen too long"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"TextLen too long"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4086" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "TextLen too long") == 1) { ::sal_detail_log( (::
SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4086" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TextLen too long"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"TextLen too long"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4086" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4087 nTextLen = nMaxPossible;
4088 }
4089 WW8_CP nTextEnd = nStartCp+nTextLen;
4090 while (l < nTextEnd)
4091 {
4092 ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4093 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode")do { if (true && (!(m_pPaM->GetNode().GetTextNode(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4093" ": "), "%s", "Missing txtnode"); } } while (false
)
;
4094
4095 if (m_pPostProcessAttrsInfo != nullptr)
4096 PostProcessAttrs();
4097
4098 if (l >= nTextEnd)
4099 break;
4100
4101 bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4102
4103 // If the previous paragraph was a dropcap then do not
4104 // create a new txtnode and join the two paragraphs together
4105 if (bStartLine && !m_pPreviousNode) // Line end
4106 {
4107 bool bSplit = true;
4108 if (m_bCareFirstParaEndInToc)
4109 {
4110 m_bCareFirstParaEndInToc = false;
4111 if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4112 bSplit = false;
4113 }
4114 if (m_bCareLastParaEndInToc)
4115 {
4116 m_bCareLastParaEndInToc = false;
4117 if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4118 bSplit = false;
4119 }
4120 if (bSplit)
4121 {
4122 // We will record the CP of a paragraph end ('0x0D'), if current loading contents is from main stream;
4123 if (m_bOnLoadingMain)
4124 m_aEndParaPos.push_back(l-1);
4125 AppendTextNode(*m_pPaM->GetPoint());
4126 }
4127 }
4128
4129 if (m_pPreviousNode && bStartLine)
4130 {
4131 SwTextNode* pEndNd = m_pPaM->GetNode().GetTextNode();
4132 const sal_Int32 nDropCapLen = m_pPreviousNode->GetText().getLength();
4133
4134 // Need to reset the font size and text position for the dropcap
4135 {
4136 SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4137 m_xCtrlStck->Delete(aTmp);
4138 }
4139
4140 // Get the default document dropcap which we can use as our template
4141 const SwFormatDrop* defaultDrop =
4142 static_cast<const SwFormatDrop*>( GetFormatAttr(RES_PARATR_DROP));
4143 SwFormatDrop aDrop(*defaultDrop);
4144
4145 aDrop.GetLines() = nDropLines;
4146 aDrop.GetDistance() = nDistance;
4147 aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4148 // Word has no concept of a "whole word dropcap"
4149 aDrop.GetWholeWord() = false;
4150
4151 if (pFormat)
4152 aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4153 else if(pNewSwCharFormat)
4154 aDrop.SetCharFormat(pNewSwCharFormat);
4155
4156 SwPosition aStart(*pEndNd);
4157 m_xCtrlStck->NewAttr(aStart, aDrop);
4158 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4159 m_pPreviousNode = nullptr;
4160 }
4161 else if (m_bDropCap)
4162 {
4163 // If we have found a dropcap store the textnode
4164 m_pPreviousNode = m_pPaM->GetNode().GetTextNode();
4165
4166 SprmResult aDCS;
4167 if (m_bVer67)
4168 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(46);
4169 else
4170 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4171
4172 if (aDCS.pSprm && aDCS.nRemainingData >= 1)
4173 nDropLines = (*aDCS.pSprm) >> 3;
4174 else // There is no Drop Cap Specifier hence no dropcap
4175 m_pPreviousNode = nullptr;
4176
4177 SprmResult aDistance = m_xPlcxMan->GetPapPLCF()->HasSprm(0x842F);
4178 if (aDistance.pSprm && aDistance.nRemainingData >= 2)
4179 nDistance = SVBT16ToUInt16(aDistance.pSprm);
4180 else
4181 nDistance = 0;
4182
4183 const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4184
4185 if (m_xCurrentItemSet)
4186 pSwFormatCharFormat = &(ItemGet<SwFormatCharFormat>(*m_xCurrentItemSet, RES_TXTATR_CHARFMT));
4187
4188 if (pSwFormatCharFormat)
4189 pFormat = pSwFormatCharFormat->GetCharFormat();
4190
4191 if (m_xCurrentItemSet && !pFormat)
4192 {
4193 OUString sPrefix = "WW8Dropcap" + OUString::number(m_nDropCap++);
4194 pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4195 m_xCurrentItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4196 pNewSwCharFormat->SetFormatAttr(*m_xCurrentItemSet);
4197 }
4198
4199 m_xCurrentItemSet.reset();
4200 m_bDropCap=false;
4201 }
4202
4203 if (bStartLine || m_bWasTabRowEnd)
4204 {
4205 // Call all 64 CRs; not for Header and the like
4206 if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT && l <= nTextLen)
4207 {
4208 if (nTextLen < WW8_CP_MAX/100)
4209 m_nProgress = static_cast<sal_uInt16>(l * 100 / nTextLen);
4210 else
4211 m_nProgress = static_cast<sal_uInt16>(l / nTextLen * 100);
4212 m_xProgress->Update(m_nProgress); // Update
4213 }
4214 }
4215
4216 // If we have encountered a 0x0c which indicates either section of
4217 // pagebreak then look it up to see if it is a section break, and
4218 // if it is not then insert a page break. If it is a section break
4219 // it will be handled as such in the ReadAttrs of the next loop
4220 if (m_bPgSecBreak)
4221 {
4222 // We need only to see if a section is ending at this cp,
4223 // the plcf will already be sitting on the correct location
4224 // if it is there.
4225 WW8PLCFxDesc aTemp;
4226 aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4227 if (m_xPlcxMan->GetSepPLCF())
4228 m_xPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4229 if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4230 {
4231 // #i39251# - insert text node for page break, if no one inserted.
4232 // #i43118# - refine condition: the anchor
4233 // control stack has to have entries, otherwise it's not needed
4234 // to insert a text node.
4235 if (!bStartLine && !m_xAnchorStck->empty())
4236 {
4237 AppendTextNode(*m_pPaM->GetPoint());
4238 }
4239 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM,
4240 SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4241 m_bFirstParaOfPage = true;
4242 m_bPgSecBreak = false;
4243 }
4244 }
4245 }
4246
4247 m_pPreviousNode = nullptr;
4248
4249 if (m_pPaM->GetPoint()->nContent.GetIndex())
4250 AppendTextNode(*m_pPaM->GetPoint());
4251
4252 if (!m_bInHyperlink)
4253 bJoined = JoinNode(*m_pPaM);
4254
4255 CloseAttrEnds();
4256
4257 m_xPlcxMan.reset();
4258 return bJoined;
4259}
4260
4261SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara, SotStorage* pStorage,
4262 SvStream* pSt, SwDoc& rD, const OUString& rBaseURL, bool bNewDoc, bool bSkipImages, SwPosition const &rPos)
4263 : m_pDocShell(rD.GetDocShell())
4264 , m_pStg(pStorage)
4265 , m_pStrm(pSt)
4266 , m_pTableStream(nullptr)
4267 , m_pDataStream(nullptr)
4268 , m_rDoc(rD)
4269 , m_pPaM(nullptr)
4270 , m_aSectionManager(*this)
4271 , m_aExtraneousParas(rD)
4272 , m_aInsertedTables(rD)
4273 , m_aSectionNameGenerator(rD, "WW")
4274 , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4275 , m_aParaStyleMapper(rD)
4276 , m_aCharStyleMapper(rD)
4277 , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4278 , m_pFormatOfJustInsertedApo(nullptr)
4279 , m_pPreviousNumPaM(nullptr)
4280 , m_pPrevNumRule(nullptr)
4281 , m_aTextNodesHavingFirstLineOfstSet()
4282 , m_aTextNodesHavingLeftIndentSet()
4283 , m_pCurrentColl(nullptr)
4284 , m_pDfltTextFormatColl(nullptr)
4285 , m_pStandardFormatColl(nullptr)
4286 , m_pDrawModel(nullptr)
4287 , m_pDrawPg(nullptr)
4288 , m_pNumFieldType(nullptr)
4289 , m_sBaseURL(rBaseURL)
4290 , m_nIniFlags(0)
4291 , m_nIniFlags1(0)
4292 , m_nFieldFlags(0)
4293 , m_bRegardHindiDigits( false )
4294 , m_bDrawCpOValid( false )
4295 , m_nDrawCpO(0)
4296 , m_nPicLocFc(0)
4297 , m_nObjLocFc(0)
4298 , m_nIniFlyDx(0)
4299 , m_nIniFlyDy(0)
4300 , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US(((rtl_TextEncoding) 11)))
4301 , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US(((rtl_TextEncoding) 11)))
4302 , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)))
4303 , m_nProgress(0)
4304 , m_nCurrentColl(0)
4305 , m_nFieldNum(0)
4306 , m_nLFOPosition(USHRT_MAX(32767 *2 +1))
4307 , m_nCharFormat(0)
4308 , m_nDrawXOfs(0)
4309 , m_nDrawYOfs(0)
4310 , m_nDrawXOfs2(0)
4311 , m_nDrawYOfs2(0)
4312 , m_cSymbol(0)
4313 , m_nWantedVersion(nVersionPara)
4314 , m_nSwNumLevel(0xff)
4315 , m_nWwNumType(0xff)
4316 , m_nListLevel(WW8ListManager::nMaxLevel)
4317 , m_bNewDoc(bNewDoc)
4318 , m_bSkipImages(bSkipImages)
4319 , m_bReadNoTable(false)
4320 , m_bPgSecBreak(false)
4321 , m_bSpec(false)
4322 , m_bObj(false)
4323 , m_bTxbxFlySection(false)
4324 , m_bHasBorder(false)
4325 , m_bSymbol(false)
4326 , m_bIgnoreText(false)
4327 , m_nInTable(0)
4328 , m_bWasTabRowEnd(false)
4329 , m_bWasTabCellEnd(false)
4330 , m_bAnl(false)
4331 , m_bHdFtFootnoteEdn(false)
4332 , m_bFootnoteEdn(false)
4333 , m_bIsHeader(false)
4334 , m_bIsFooter(false)
4335 , m_bIsUnicode(false)
4336 , m_bCpxStyle(false)
4337 , m_bStyNormal(false)
4338 , m_bWWBugNormal(false)
4339 , m_bNoAttrImport(false)
4340 , m_bInHyperlink(false)
4341 , m_bWasParaEnd(false)
4342 , m_bVer67(false)
4343 , m_bVer6(false)
4344 , m_bVer7(false)
4345 , m_bVer8(false)
4346 , m_bEmbeddObj(false)
4347 , m_bCurrentAND_fNumberAcross(false)
4348 , m_bNoLnNumYet(true)
4349 , m_bFirstPara(true)
4350 , m_bFirstParaOfPage(false)
4351 , m_bParaAutoBefore(false)
4352 , m_bParaAutoAfter(false)
4353 , m_bDropCap(false)
4354 , m_nDropCap(0)
4355 , m_bBidi(false)
4356 , m_bReadTable(false)
4357 , m_bLoadingTOXCache(false)
4358 , m_nEmbeddedTOXLevel(0)
4359 , m_bLoadingTOXHyperlink(false)
4360 , m_pPreviousNode(nullptr)
4361 , m_bCareFirstParaEndInToc(false)
4362 , m_bCareLastParaEndInToc(false)
4363 , m_aTOXEndCps()
4364 , m_aCurrAttrCP(-1)
4365 , m_bOnLoadingMain(false)
4366 , m_bNotifyMacroEventRead(false)
4367{
4368 m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4369 m_aApos.push_back(false);
4370
4371 mpCursor = m_rDoc.CreateUnoCursor(rPos);
4372}
4373
4374SwWW8ImplReader::~SwWW8ImplReader()
4375{
4376}
4377
4378void SwWW8ImplReader::DeleteStack(std::unique_ptr<SwFltControlStack> pStck)
4379{
4380 if( pStck )
4381 {
4382 pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4383 pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4384 }
4385 else
4386 {
4387 OSL_ENSURE( false, "WW stack already deleted" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4387" ": "), "%s", "WW stack already deleted"); } } while
(false)
;
4388 }
4389}
4390
4391void wwSectionManager::SetSegmentToPageDesc(const wwSection &rSection,
4392 bool bIgnoreCols)
4393{
4394 SwPageDesc &rPage = *rSection.mpPage;
4395
4396 SetNumberingType(rSection, rPage);
4397
4398 SwFrameFormat &rFormat = rPage.GetMaster();
4399
4400 if(mrReader.m_xWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4401 mrReader.GrafikCtor();
4402
4403 if (mrReader.m_xWDop->fUseBackGroundInAllmodes && mrReader.m_xMSDffManager)
4404 {
4405 tools::Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4406 SvxMSDffImportData aData(aRect);
4407 SdrObject* pObject = nullptr;
4408 if (mrReader.m_xMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4409 {
4410 // Only handle shape if it is a background shape
4411 if (aData.begin()->get()->nFlags & ShapeFlag::Background)
4412 {
4413 SfxItemSet aSet(rFormat.GetDoc()->GetAttrPool(),
4414 svl::Items<RES_BACKGROUND, RES_BACKGROUND,XATTR_START, XATTR_END>{});
4415 mrReader.MatchSdrItemsIntoFlySet(pObject, aSet, mso_lineSimple,
4416 mso_lineSolid, mso_sptRectangle, aRect);
4417 if ( aSet.HasItem(RES_BACKGROUND) )
4418 rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4419 else
4420 rFormat.SetFormatAttr(aSet);
4421 }
4422 }
4423 SdrObject::Free(pObject);
4424 }
4425 wwULSpaceData aULData;
4426 GetPageULData(rSection, aULData);
4427 SetPageULSpaceItems(rFormat, aULData, rSection);
4428
4429 rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4430
4431 SetPage(rPage, rFormat, rSection, bIgnoreCols);
4432
4433 if (!(rSection.maSep.pgbApplyTo & 1))
4434 SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4435 if (!(rSection.maSep.pgbApplyTo & 2))
4436 SwWW8ImplReader::SetPageBorder(rPage.GetFirstMaster(), rSection);
4437
4438 mrReader.SetDocumentGrid(rFormat, rSection);
4439}
4440
4441void wwSectionManager::SetUseOn(wwSection &rSection)
4442{
4443 bool bMirror = mrReader.m_xWDop->fMirrorMargins ||
4444 mrReader.m_xWDop->doptypography.m_f2on1;
4445
4446 UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4447 UseOnPage eUse = eUseBase;
4448 if (!mrReader.m_xWDop->fFacingPages)
4449 eUse |= UseOnPage::HeaderShare | UseOnPage::FooterShare;
4450 if (!rSection.HasTitlePage())
4451 eUse |= UseOnPage::FirstShare;
4452
4453 OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set")do { if (true && (!(rSection.mpPage))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4453" ": "), "%s", "Makes no sense to call me with no pages to set"
); } } while (false)
;
4454 if (rSection.mpPage)
4455 rSection.mpPage->WriteUseOn(eUse);
4456}
4457
4458/**
4459 * Set the page descriptor on this node, handle the different cases for a text
4460 * node or a table
4461 */
4462static void GiveNodePageDesc(SwNodeIndex const &rIdx, const SwFormatPageDesc &rPgDesc,
4463 SwDoc &rDoc)
4464{
4465 /*
4466 If it's a table here, apply the pagebreak to the table
4467 properties, otherwise we add it to the para at this
4468 position
4469 */
4470 if (rIdx.GetNode().IsTableNode())
4471 {
4472 SwTable& rTable =
4473 rIdx.GetNode().GetTableNode()->GetTable();
4474 SwFrameFormat* pApply = rTable.GetFrameFormat();
4475 OSL_ENSURE(pApply, "impossible")do { if (true && (!(pApply))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4475" ": "), "%s", "impossible"); } } while (false)
;
4476 if (pApply)
4477 pApply->SetFormatAttr(rPgDesc);
4478 }
4479 else
4480 {
4481 SwPosition aPamStart(rIdx);
4482 aPamStart.nContent.Assign(
4483 rIdx.GetNode().GetContentNode(), 0);
4484 SwPaM aPage(aPamStart);
4485
4486 rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4487 }
4488}
4489
4490/**
4491 * Map a word section to a writer page descriptor
4492 */
4493SwFormatPageDesc wwSectionManager::SetSwFormatPageDesc(mySegIter const &rIter,
4494 mySegIter const &rStart, bool bIgnoreCols)
4495{
4496 if (mrReader.m_bNewDoc && rIter == rStart)
4497 {
4498 rIter->mpPage =
4499 mrReader.m_rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD);
4500 }
4501 else
4502 {
4503 rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4504 SwViewShell::GetShellRes()->GetPageDescName(mnDesc, ShellResource::NORMAL_PAGE),
4505 nullptr, false);
4506 }
4507 OSL_ENSURE(rIter->mpPage, "no page!")do { if (true && (!(rIter->mpPage))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4507" ": "), "%s", "no page!"); } } while (false)
;
4508 if (!rIter->mpPage)
4509 return SwFormatPageDesc();
4510
4511 // Set page before hd/ft
4512 const wwSection *pPrevious = nullptr;
4513 if (rIter != rStart)
4514 pPrevious = &(*(rIter-1));
4515 SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4516 SetUseOn(*rIter);
4517
4518 // Set hd/ft after set page
4519 SetSegmentToPageDesc(*rIter, bIgnoreCols);
4520
4521 SwFormatPageDesc aRet(rIter->mpPage);
4522
4523 rIter->mpPage->SetFollow(rIter->mpPage);
4524
4525 if (rIter->PageRestartNo())
4526 aRet.SetNumOffset(rIter->PageStartAt());
4527
4528 ++mnDesc;
4529 return aRet;
4530}
4531
4532void wwSectionManager::InsertSegments()
4533{
4534 mySegIter aEnd = maSegments.end();
4535 mySegIter aStart = maSegments.begin();
4536 for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4537 {
4538 // If the section is of type "New column" (0x01), then simply insert a column break.
4539 // But only if there actually are columns on the page, otherwise a column break
4540 // seems to be handled like a page break by MSO.
4541 if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4542 {
4543 SwPaM start( aIter->maStart );
4544 mrReader.m_rDoc.getIDocumentContentOperations().InsertPoolItem( start, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
4545 continue;
4546 }
4547
4548 mySegIter aNext = aIter+1;
4549 mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4550
4551 // If two following sections are different in following properties, Word will interpret a continuous
4552 // section break between them as if it was a section break next page.
4553 bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4554 (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4555
4556 bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() && bThisAndPreviousAreCompatible;
4557 bool bInsertPageDesc = !bInsertSection;
4558 // HACK Force new pagedesc if left/right margins change, otherwise e.g. floating tables may be anchored improperly.
4559 if( aIter->maSep.dxaLeft != aPrev->maSep.dxaLeft || aIter->maSep.dxaRight != aPrev->maSep.dxaRight )
4560 bInsertPageDesc = true;
4561 bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4562
4563 if (bInsertPageDesc)
4564 {
4565 /*
4566 If a cont section follows this section then we won't be
4567 creating a page desc with 2+ cols as we cannot host a one
4568 col section in a 2+ col pagedesc and make it look like
4569 word. But if the current section actually has columns then
4570 we are forced to insert a section here as well as a page
4571 descriptor.
4572 */
4573
4574 bool bIgnoreCols = bInsertSection;
4575 bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4576 ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4577 (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4578 (aIter->IsLandScape() == aNext->IsLandScape()));
4579
4580 if ((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected)
4581 {
4582 bIgnoreCols = true;
4583 if ((aIter->NoCols() > 1) || bProtected)
4584 bInsertSection = true;
4585 }
4586
4587 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4588 if (!aDesc.GetPageDesc())
4589 continue;
4590
4591 // special case handling for odd/even section break
4592 // a) as before create a new page style for the section break
4593 // b) set Layout of generated page style to right/left ( according
4594 // to section break odd/even )
4595 // c) create a new style to follow the break page style
4596 if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4597 {
4598 // SetSwFormatPageDesc calls some methods that could
4599 // modify aIter (e.g. wwSection ).
4600 // Since we call SetSwFormatPageDesc below to generate the
4601 // 'Following' style of the Break style, it is safer
4602 // to take a copy of the contents of aIter.
4603 wwSection aTmpSection = *aIter;
4604 // create a new following page style
4605 SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4606 // restore any contents of aIter trashed by SetSwFormatPageDesc
4607 *aIter = aTmpSection;
4608
4609 // Handle the section break
4610 UseOnPage eUseOnPage = UseOnPage::Left;
4611 if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4612 eUseOnPage = UseOnPage::Right;
4613
4614 // Keep the share flags.
4615 aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4616 aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4617 }
4618
4619 GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4620 }
4621
4622 SwTextNode* pTextNd = nullptr;
4623 if (bInsertSection)
4624 {
4625 // Start getting the bounds of this section
4626 SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4627 SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4628 if (aNext != aEnd)
4629 {
4630 aAnchor = aNext->maStart;
4631 aSectPaM.GetPoint()->nNode = aAnchor;
4632 aSectPaM.GetPoint()->nContent.Assign(
4633 aNext->maStart.GetNode().GetContentNode(), 0);
4634 aSectPaM.Move(fnMoveBackward);
4635 }
4636
4637 const SwPosition* pPos = aSectPaM.GetPoint();
4638 SwTextNode const*const pSttNd = pPos->nNode.GetNode().GetTextNode();
4639 const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4640 if (pTableNd)
4641 {
4642 pTextNd =
4643 mrReader.m_rDoc.GetNodes().MakeTextNode(aAnchor,
4644 mrReader.m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ));
4645
4646 aSectPaM.GetPoint()->nNode.Assign(*pTextNd);
4647 aSectPaM.GetPoint()->nContent.Assign(
4648 aSectPaM.GetContentNode(), 0);
4649 }
4650
4651 aSectPaM.SetMark();
4652
4653 aSectPaM.GetPoint()->nNode = aIter->maStart;
4654 aSectPaM.GetPoint()->nContent.Assign(
4655 aSectPaM.GetContentNode(), 0);
4656
4657 bool bHasOwnHdFt = false;
4658 /*
4659 In this nightmare scenario the continuous section has its own
4660 headers and footers so we will try and find a hard page break
4661 between here and the end of the section and put the headers and
4662 footers there.
4663 */
4664 if (!bInsertPageDesc)
4665 {
4666 bHasOwnHdFt =
4667 mrReader.HasOwnHeaderFooter(
4668 aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4669 aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4670 );
4671 }
4672 if (bHasOwnHdFt)
4673 {
4674 // #i40766# Need to cache the page descriptor in case there is
4675 // no page break in the section
4676 SwPageDesc *pOrig = aIter->mpPage;
4677 bool bFailed = true;
4678 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4679 if (aDesc.GetPageDesc())
4680 {
4681 sal_uLong nStart = aSectPaM.Start()->nNode.GetIndex();
4682 sal_uLong nEnd = aSectPaM.End()->nNode.GetIndex();
4683 for(; nStart <= nEnd; ++nStart)
4684 {
4685 SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4686 if (!pNode)
4687 continue;
4688 if (sw::util::HasPageBreak(*pNode))
4689 {
4690 SwNodeIndex aIdx(*pNode);
4691 GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4692 bFailed = false;
4693 break;
4694 }
4695 }
4696 }
4697 if(bFailed)
4698 {
4699 aIter->mpPage = pOrig;
4700 }
4701 }
4702
4703 // End getting the bounds of this section, quite a job eh?
4704 SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4705 // The last section if continuous is always unbalanced
4706 if (pRet)
4707 {
4708 // Set the columns to be UnBalanced if that compatibility option is set
4709 if (mrReader.m_xWDop->fNoColumnBalance)
4710 pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4711 else
4712 {
4713 // Otherwise set to unbalanced if the following section is
4714 // not continuous, (which also means that the last section
4715 // is unbalanced)
4716 if (aNext == aEnd || !aNext->IsContinuous())
4717 pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4718 }
4719 }
4720 }
4721
4722 if (pTextNd)
4723 {
4724 SwNodeIndex aIdx(*pTextNd);
4725 SwPaM aTest(aIdx);
4726 mrReader.m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4727 pTextNd = nullptr;
4728 }
4729 }
4730}
4731
4732void wwExtraneousParas::delete_all_from_doc()
4733{
4734 auto aEnd = m_aTextNodes.rend();
4735 for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4736 {
4737 SwTextNode *pTextNode = *aI;
4738 SwNodeIndex aIdx(*pTextNode);
4739 SwPaM aTest(aIdx);
4740 m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4741 }
4742 m_aTextNodes.clear();
4743}
4744
4745void SwWW8ImplReader::StoreMacroCmds()
4746{
4747 if (!m_xWwFib->m_lcbCmds)
4748 return;
4749
4750 bool bValidPos = checkSeek(*m_pTableStream, m_xWwFib->m_fcCmds);
4751 if (!bValidPos)
4752 return;
4753
4754 uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4755
4756 if (!xRoot.is())
4757 return;
4758
4759 try
4760 {
4761 uno::Reference < io::XStream > xStream =
4762 xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4763 std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4764
4765 sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_xWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4766 std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4767 m_xWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4768 xOutStream->WriteBytes(xBuffer.get(), m_xWwFib->m_lcbCmds);
4769 }
4770 catch (...)
4771 {
4772 }
4773}
4774
4775void SwWW8ImplReader::ReadDocVars()
4776{
4777 std::vector<OUString> aDocVarStrings;
4778 std::vector<ww::bytes> aDocVarStringIds;
4779 std::vector<OUString> aDocValueStrings;
4780 WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcStwUser,
4781 m_xWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4782 aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4783 if (m_bVer67) return;
4784
4785 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4786 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4787 uno::Reference<document::XDocumentProperties> xDocProps(
4788 xDPS->getDocumentProperties());
4789 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null")do { if (true && (!(xDocProps.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4789" ": "), "%s", "DocumentProperties is null"); } } while
(false)
;
4790 uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4791 xDocProps->getUserDefinedProperties();
4792 OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null")do { if (true && (!(xUserDefinedProps.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4792" ": "), "%s", "UserDefinedProperties is null"); } }
while (false)
;
4793
4794 for(size_t i=0; i<aDocVarStrings.size(); i++)
4795 {
4796 const OUString &rName = aDocVarStrings[i];
4797 uno::Any aValue;
4798 aValue <<= rName;
4799 try {
4800 xUserDefinedProps->addProperty( rName,
4801 beans::PropertyAttribute::REMOVABLE,
4802 aValue );
4803 } catch (const uno::Exception &) {
4804 // ignore
4805 }
4806 }
4807}
4808
4809/**
4810 * Document Info
4811 */
4812void SwWW8ImplReader::ReadDocInfo()
4813{
4814 if( !m_pStg )
4815 return;
4816
4817 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4818 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4819 uno::Reference<document::XDocumentProperties> xDocProps(
4820 xDPS->getDocumentProperties());
4821 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null")do { if (true && (!(xDocProps.is()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4821" ": "), "%s", "DocumentProperties is null"); } } while
(false)
;
4822
4823 if (!xDocProps.is())
4824 return;
4825
4826 if ( m_xWwFib->m_fDot )
4827 {
4828 SfxMedium* pMedium = m_pDocShell->GetMedium();
4829 if ( pMedium )
4830 {
4831 const OUString& aName = pMedium->GetName();
4832 INetURLObject aURL( aName );
4833 OUString sTemplateURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
4834 if ( !sTemplateURL.isEmpty() )
4835 xDocProps->setTemplateURL( sTemplateURL );
4836 }
4837 }
4838 else if (m_xWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4839 {
4840 auto nCur = m_pTableStream->Tell();
4841 Sttb aSttb;
4842 // point at tgc record
4843 if (!checkSeek(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc) || !aSttb.Read(*m_pTableStream))
4844 SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "** Read of SttbAssoc data failed!!!! "
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4844" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Read of SttbAssoc data failed!!!! "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Read of SttbAssoc data failed!!!! "; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4844" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "** Read of SttbAssoc data failed!!!! ") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4844" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Read of SttbAssoc data failed!!!! "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Read of SttbAssoc data failed!!!! "; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4844" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4845 m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4846 OUString sPath = aSttb.getStringAtIndex( 0x1 );
4847 OUString aURL;
4848 // attempt to convert to url (won't work for obvious reasons on linux)
4849 if ( !sPath.isEmpty() )
4850 osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4851 if (aURL.isEmpty())
4852 xDocProps->setTemplateURL( aURL );
4853 else
4854 xDocProps->setTemplateURL( sPath );
4855
4856 }
4857 sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4858}
4859
4860static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4861{
4862 if ( !xPrjNameCache.is() )
4863 return;
4864
4865 INetURLObject aObj;
4866 aObj.SetURL( sTemplatePathOrURL );
4867 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4868 OUString aURL;
4869 if ( bIsURL )
4870 aURL = sTemplatePathOrURL;
4871 else
4872 {
4873 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4874 aObj.SetURL( aURL );
4875 }
4876 try
4877 {
4878 OUString templateNameWithExt = aObj.GetLastName();
4879 sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4880 if ( nIndex != -1 )
4881 {
4882 OUString templateName = templateNameWithExt.copy( 0, nIndex );
4883 xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4884 }
4885 }
4886 catch( const uno::Exception& )
4887 {
4888 }
4889}
4890
4891namespace {
4892
4893class WW8Customizations
4894{
4895 SvStream* mpTableStream;
4896 WW8Fib mWw8Fib;
4897public:
4898 WW8Customizations( SvStream*, WW8Fib const & );
4899 void Import( SwDocShell* pShell );
4900};
4901
4902}
4903
4904WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4905{
4906}
4907
4908void WW8Customizations::Import( SwDocShell* pShell )
4909{
4910 if ( mWw8Fib.m_lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4911 return;
4912 try
4913 {
4914 Tcg aTCG;
4915 long nCur = mpTableStream->Tell();
4916 if (!checkSeek(*mpTableStream, mWw8Fib.m_fcCmds)) // point at tgc record
4917 {
4918 SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "** Seek to Customization data failed!!!! "
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4918" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Seek to Customization data failed!!!! "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Seek to Customization data failed!!!! "; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4918" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "** Seek to Customization data failed!!!! ") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4918" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Seek to Customization data failed!!!! "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Seek to Customization data failed!!!! "; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4918" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4919 return;
4920 }
4921 bool bReadResult = aTCG.Read( *mpTableStream );
4922 mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4923 if ( !bReadResult )
4924 {
4925 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "** Read of Customization data failed!!!! "
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4925" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Read of Customization data failed!!!! "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Read of Customization data failed!!!! "; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4925" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "** Read of Customization data failed!!!! ") == 1
) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4925" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Read of Customization data failed!!!! "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Read of Customization data failed!!!! "; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4925" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4926 return;
4927 }
4928 aTCG.ImportCustomToolBar( *pShell );
4929 }
4930 catch(...)
4931 {
4932 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "** Read of Customization data failed!!!! epically"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4932" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Read of Customization data failed!!!! epically"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Read of Customization data failed!!!! epically"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4932" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "** Read of Customization data failed!!!! epically"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4932" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "** Read of Customization data failed!!!! epically"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "** Read of Customization data failed!!!! epically"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "4932" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
4933 }
4934}
4935
4936void SwWW8ImplReader::ReadGlobalTemplateSettings( const OUString& sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4937{
4938 if (utl::ConfigManager::IsFuzzing())
4939 return;
4940
4941 SvtPathOptions aPathOpt;
4942 const OUString& aAddinPath = aPathOpt.GetAddinPath();
4943 uno::Sequence< OUString > sGlobalTemplates;
4944
4945 // first get the autoload addins in the directory STARTUP
4946 uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4947
4948 if( xSFA->isFolder( aAddinPath ) )
4949 sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4950
4951 for ( const auto& rGlobalTemplate : std::as_const(sGlobalTemplates) )
4952 {
4953 INetURLObject aObj;
4954 aObj.SetURL( rGlobalTemplate );
4955 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4956 OUString aURL;
4957 if ( bIsURL )
4958 aURL = rGlobalTemplate;
4959 else
4960 osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate, aURL );
4961 if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.isEmpty() && sCreatedFrom == aURL ) )
4962 continue; // don't try and read the same document as ourselves
4963
4964 tools::SvRef<SotStorage> rRoot = new SotStorage( aURL, StreamMode::STD_READWRITE );
4965
4966 BasicProjImportHelper aBasicImporter( *m_pDocShell );
4967 // Import vba via oox filter
4968 aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
4969 lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4970 // Read toolbars & menus
4971 tools::SvRef<SotStorageStream> refMainStream = rRoot->OpenSotStream( "WordDocument");
4972 refMainStream->SetEndian(SvStreamEndian::LITTLE);
4973 WW8Fib aWwFib( *refMainStream, 8 );
4974 tools::SvRef<SotStorageStream> xTableStream =
4975 rRoot->OpenSotStream(aWwFib.m_fWhichTableStm ? SL::a1Table : SL::a0Table, StreamMode::STD_READ);
4976
4977 if (xTableStream.is() && ERRCODE_NONEErrCode(0) == xTableStream->GetError())
4978 {
4979 xTableStream->SetEndian(SvStreamEndian::LITTLE);
4980 WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
4981 aGblCustomisations.Import( m_pDocShell );
4982 }
4983 }
4984}
4985
4986ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss)
4987{
4988 m_rDoc.SetDocumentType( SwDoc::DOCTYPE_MSWORD );
4989 if (m_bNewDoc && m_pStg && !pGloss)
4990 {
4991 // Initialize RDF metadata, to be able to add statements during the import.
4992 try
4993 {
4994 uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
4995 uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
4996 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
4997 uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
4998 const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
4999 uno::Reference<task::XInteractionHandler> xHandler;
5000 xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
5001 }
5002 catch (const uno::Exception&)
5003 {
5004 TOOLS_WARN_EXCEPTION("sw.ww8", "failed to initialize RDF metadata")do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "failed to initialize RDF metadata"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5004" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "failed to initialize RDF metadata" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "failed to initialize RDF metadata" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5004" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "failed to initialize RDF metadata" << " " <<
exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5004" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "failed to initialize RDF metadata" <<
" " << exceptionToString(tools_warn_exception)), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "failed to initialize RDF metadata" << " " <<
exceptionToString(tools_warn_exception); ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5004" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
5005 }
5006 ReadDocInfo();
5007 }
5008
5009 auto pFibData = std::make_shared<::ww8::WW8FibData>();
5010
5011 if (m_xWwFib->m_fReadOnlyRecommended)
5012 pFibData->setReadOnlyRecommended(true);
5013 else
5014 pFibData->setReadOnlyRecommended(false);
5015
5016 if (m_xWwFib->m_fWriteReservation)
5017 pFibData->setWriteReservation(true);
5018 else
5019 pFibData->setWriteReservation(false);
5020
5021 m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB, pFibData);
5022
5023 ::sw::tExternalDataPointer pSttbfAsoc
5024 = std::make_shared<::ww8::WW8Sttb<ww8::WW8Struct>>(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc, m_xWwFib->m_lcbSttbfAssoc);
5025
5026 m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC, pSttbfAsoc);
5027
5028 if (m_xWwFib->m_fWriteReservation || m_xWwFib->m_fReadOnlyRecommended)
5029 {
5030 SwDocShell * pDocShell = m_rDoc.GetDocShell();
5031 if (pDocShell)
5032 pDocShell->SetReadOnlyUI();
5033 }
5034
5035 m_pPaM = mpCursor.get();
5036
5037 m_xCtrlStck.reset(new SwWW8FltControlStack(m_rDoc, m_nFieldFlags, *this));
5038
5039 m_xRedlineStack.reset(new sw::util::RedlineStack(m_rDoc));
5040
5041 /*
5042 RefFieldStck: Keeps track of bookmarks which may be inserted as
5043 variables instead.
5044 */
5045 m_xReffedStck.reset(new SwWW8ReferencedFltEndStack(m_rDoc, m_nFieldFlags));
5046 m_xReffingStck.reset(new SwWW8FltRefStack(m_rDoc, m_nFieldFlags));
5047
5048 m_xAnchorStck.reset(new SwWW8FltAnchorStack(m_rDoc, m_nFieldFlags));
5049
5050 size_t nPageDescOffset = m_rDoc.GetPageDescCnt();
5051
5052 SwNodeIndex aSttNdIdx( m_rDoc.GetNodes() );
5053
5054 RedlineFlags eMode = RedlineFlags::ShowInsert | RedlineFlags::ShowDelete;
5055
5056 m_xSprmParser.reset(new wwSprmParser(*m_xWwFib));
5057
5058 // Set handy helper variables
5059 m_bVer6 = (6 == m_xWwFib->m_nVersion);
5060 m_bVer7 = (7 == m_xWwFib->m_nVersion);
5061 m_bVer67 = m_bVer6 || m_bVer7;
5062 m_bVer8 = (8 == m_xWwFib->m_nVersion);
5063
5064 m_eTextCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chse, m_xWwFib->m_lid);
5065 m_eStructCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chseTables, m_xWwFib->m_lid);
5066
5067 m_bWWBugNormal = m_xWwFib->m_nProduct == 0xc03d;
5068
5069 if (!m_bNewDoc)
5070 aSttNdIdx = m_pPaM->GetPoint()->nNode;
5071
5072 m_xProgress.reset(new ImportProgress(m_pDocShell, 0, 100));
5073
5074 // read Font Table
5075 m_xFonts.reset(new WW8Fonts(*m_pTableStream, *m_xWwFib));
5076
5077 // Document Properties
5078 m_xWDop.reset(new WW8Dop(*m_pTableStream, m_xWwFib->m_nFib, m_xWwFib->m_fcDop,
5079 m_xWwFib->m_lcbDop));
5080
5081 if (m_bNewDoc)
5082 ImportDop();
5083
5084 /*
5085 Import revisioning data: author names
5086 */
5087 if( m_xWwFib->m_lcbSttbfRMark )
5088 {
5089 ReadRevMarkAuthorStrTabl(*m_pTableStream,
5090 m_xWwFib->m_fcSttbfRMark,
5091 m_xWwFib->m_lcbSttbfRMark, m_rDoc);
5092 }
5093
5094 // Initialize our String/ID map for Linked Sections
5095 std::vector<OUString> aLinkStrings;
5096 std::vector<ww::bytes> aStringIds;
5097
5098 WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcSttbFnm,
5099 m_xWwFib->m_lcbSttbFnm, m_bVer67 ? 2 : 0, m_eStructCharSet,
5100 aLinkStrings, &aStringIds);
5101
5102 for (size_t i=0; i < aLinkStrings.size() && i < aStringIds.size(); ++i)
5103 {
5104 const ww::bytes& stringId = aStringIds[i];
5105 if (stringId.size() < sizeof(WW8_STRINGID))
5106 {
5107 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5107" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5107" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5107" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5107" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5108 continue;
5109 }
5110 const WW8_STRINGID *stringIdStruct = reinterpret_cast<const WW8_STRINGID*>(stringId.data());
5111 m_aLinkStringMap[SVBT16ToUInt16(stringIdStruct->nStringId)] = aLinkStrings[i];
5112 }
5113
5114 ReadDocVars(); // import document variables as meta information.
5115
5116 m_xProgress->Update(m_nProgress); // Update
5117
5118 m_xLstManager.reset(new WW8ListManager(*m_pTableStream, *this));
5119
5120 /*
5121 first (1) import all styles (see WW8PAR2.CXX)
5122 BEFORE the import of the lists !!
5123 */
5124 m_xProgress->Update(m_nProgress); // Update
5125 m_xStyles.reset(new WW8RStyle(*m_xWwFib, this)); // Styles
5126 m_xStyles->Import();
5127
5128 /*
5129 In the end: (also see WW8PAR3.CXX)
5130
5131 Go through all Styles and attach respective List Format
5132 AFTER we imported the Styles and AFTER we imported the Lists!
5133 */
5134 m_xProgress->Update(m_nProgress); // Update
5135 m_xStyles->PostProcessStyles();
5136
5137 if (!m_vColl.empty())
5138 SetOutlineStyles();
5139
5140 m_xSBase.reset(new WW8ScannerBase(m_pStrm,m_pTableStream,m_pDataStream, m_xWwFib.get()));
5141
5142 if (m_xSBase->AreThereFootnotes())
5143 {
5144 static const SwFootnoteNum eNumA[4] =
5145 {
5146 FTNNUM_DOC, FTNNUM_CHAPTER, FTNNUM_PAGE, FTNNUM_DOC
5147 };
5148
5149 SwFootnoteInfo aInfo = m_rDoc.GetFootnoteInfo(); // Copy-Ctor private
5150
5151 aInfo.m_ePos = FTNPOS_PAGE;
5152 aInfo.m_eNum = eNumA[m_xWDop->rncFootnote];
5153 sal_uInt16 nfcFootnoteRef = m_xWDop->nfcFootnoteRef;
5154 aInfo.m_aFormat.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcFootnoteRef));
5155 if( m_xWDop->nFootnote )
5156 aInfo.m_nFootnoteOffset = m_xWDop->nFootnote - 1;
5157 m_rDoc.SetFootnoteInfo( aInfo );
5158 }
5159 if (m_xSBase->AreThereEndnotes())
5160 {
5161 SwEndNoteInfo aInfo = m_rDoc.GetEndNoteInfo(); // Same as for Footnote
5162 sal_uInt16 nfcEdnRef = m_xWDop->nfcEdnRef;
5163 aInfo.m_aFormat.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcEdnRef));
5164 if( m_xWDop->nEdn )
5165 aInfo.m_nFootnoteOffset = m_xWDop->nEdn - 1;
5166 m_rDoc.SetEndNoteInfo( aInfo );
5167 }
5168
5169 if (m_xWwFib->m_lcbPlcfhdd)
5170 m_xHdFt.reset(new WW8PLCF_HdFt(m_pTableStream, *m_xWwFib, *m_xWDop));
5171
5172 if (!m_bNewDoc)
5173 {
5174 // inserting into an existing document:
5175 // As only complete paragraphs are inserted, the current one
5176 // needs to be split - once or even twice.
5177 const SwPosition* pPos = m_pPaM->GetPoint();
5178
5179 // split current paragraph to get new paragraph for the insertion
5180 m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5181
5182 // another split, if insertion position was not at the end of the current paragraph.
5183 SwTextNode const*const pTextNd = pPos->nNode.GetNode().GetTextNode();
5184 if ( pTextNd->GetText().getLength() )
5185 {
5186 m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5187 // move PaM back to the newly empty paragraph
5188 m_pPaM->Move( fnMoveBackward );
5189 }
5190
5191 // suppress insertion of tables inside footnotes.
5192 const sal_uLong nNd = pPos->nNode.GetIndex();
5193 m_bReadNoTable = ( nNd < m_rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
5194 m_rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd );
5195 }
5196
5197 m_xProgress->Update(m_nProgress); // Update
5198
5199 // loop for each glossary entry and add dummy section node
5200 if (pGloss)
5201 {
5202 WW8PLCF aPlc(*m_pTableStream, m_xWwFib->m_fcPlcfglsy, m_xWwFib->m_lcbPlcfglsy, 0);
5203
5204 WW8_CP nStart, nEnd;
5205 void* pDummy;
5206
5207 for (int i = 0; i < pGloss->GetNoStrings(); ++i, aPlc.advance())
5208 {
5209 SwNodeIndex aIdx( m_rDoc.GetNodes().GetEndOfContent());
5210 SwTextFormatColl* pColl =
5211 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD,
5212 false);
5213 SwStartNode *pNode =
5214 m_rDoc.GetNodes().MakeTextSection(aIdx,
5215 SwNormalStartNode,pColl);
5216 m_pPaM->GetPoint()->nNode = pNode->GetIndex()+1;
5217 m_pPaM->GetPoint()->nContent.Assign(m_pPaM->GetContentNode(),0);
5218 aPlc.Get( nStart, nEnd, pDummy );
5219 ReadText(nStart,nEnd-nStart-1,MAN_MAINTEXT);
5220 }
5221 }
5222 else // ordinary case
5223 {
5224 if (m_bNewDoc && m_pStg) /*meaningless for a glossary */
5225 {
5226 m_pDocShell->SetIsTemplate( m_xWwFib->m_fDot ); // point at tgc record
5227 uno::Reference<document::XDocumentPropertiesSupplier> const
5228 xDocPropSupp(m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
5229 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_SET_THROW );
5230
5231 OUString sCreatedFrom = xDocProps->getTemplateURL();
5232 uno::Reference< container::XNameContainer > xPrjNameCache;
5233 uno::Reference< lang::XMultiServiceFactory> xSF(m_pDocShell->GetModel(), uno::UNO_QUERY);
5234 if ( xSF.is() )
5235 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
5236
5237 // Read Global templates
5238 ReadGlobalTemplateSettings( sCreatedFrom, xPrjNameCache );
5239
5240 // Create and insert Word vba Globals
5241 uno::Any aGlobs;
5242 uno::Sequence< uno::Any > aArgs(1);
5243 aArgs[ 0 ] <<= m_pDocShell->GetModel();
5244 try
5245 {
5246 aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs );
5247 }
5248 catch (const uno::Exception&)
5249 {
5250 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.ww8")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5250" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5250" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5250" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.ww8"
), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5250" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5251 }
5252
5253#if HAVE_FEATURE_SCRIPTING1
5254 if (!utl::ConfigManager::IsFuzzing())
5255 {
5256 BasicManager *pBasicMan = m_pDocShell->GetBasicManager();
5257 if (pBasicMan)
5258 pBasicMan->SetGlobalUNOConstant( "VBAGlobals", aGlobs );
5259 }
5260#endif
5261 BasicProjImportHelper aBasicImporter( *m_pDocShell );
5262 // Import vba via oox filter
5263 bool bRet = aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
5264
5265 lcl_createTemplateToProjectEntry( xPrjNameCache, sCreatedFrom, aBasicImporter.getProjectName() );
5266 WW8Customizations aCustomisations( m_pTableStream, *m_xWwFib );
5267 aCustomisations.Import( m_pDocShell );
5268
5269 if( bRet )
5270 m_rDoc.SetContainsMSVBasic(true);
5271
5272 StoreMacroCmds();
5273 }
5274 m_bOnLoadingMain = true;
5275 ReadText(0, m_xWwFib->m_ccpText, MAN_MAINTEXT);
5276 m_bOnLoadingMain = false;
5277 }
5278
5279 m_xProgress->Update(m_nProgress); // Update
5280
5281 if (m_pDrawPg && m_xMSDffManager && m_xMSDffManager->GetShapeOrders())
5282 {
5283 // Helper array to chain the inserted frames (instead of SdrTextObj)
5284 SvxMSDffShapeTxBxSort aTxBxSort;
5285
5286 // Ensure correct z-order of read Escher objects
5287 sal_uInt16 nShapeCount = m_xMSDffManager->GetShapeOrders()->size();
5288
5289 for (sal_uInt16 nShapeNum=0; nShapeNum < nShapeCount; nShapeNum++)
5290 {
5291 SvxMSDffShapeOrder *pOrder =
5292 (*m_xMSDffManager->GetShapeOrders())[nShapeNum].get();
5293 // Insert Pointer into new Sort array
5294 if (pOrder->nTxBxComp && pOrder->pFly)
5295 aTxBxSort.insert(pOrder);
5296 }
5297 // Chain Frames
5298 if( !aTxBxSort.empty() )
5299 {
5300 SwFormatChain aChain;
5301 for( SvxMSDffShapeTxBxSort::iterator it = aTxBxSort.begin(); it != aTxBxSort.end(); ++it )
5302 {
5303 SvxMSDffShapeOrder *pOrder = *it;
5304
5305 // Initialize FlyFrame Formats
5306 SwFlyFrameFormat* pFlyFormat = pOrder->pFly;
5307 SwFlyFrameFormat* pNextFlyFormat = nullptr;
5308 SwFlyFrameFormat* pPrevFlyFormat = nullptr;
5309
5310 // Determine successor, if we can
5311 SvxMSDffShapeTxBxSort::iterator tmpIter1 = it;
5312 ++tmpIter1;
5313 if( tmpIter1 != aTxBxSort.end() )
5314 {
5315 SvxMSDffShapeOrder *pNextOrder = *tmpIter1;
5316 if ((0xFFFF0000 & pOrder->nTxBxComp)
5317 == (0xFFFF0000 & pNextOrder->nTxBxComp))
5318 pNextFlyFormat = pNextOrder->pFly;
5319 }
5320 // Determine predecessor, if we can
5321 if( it != aTxBxSort.begin() )
5322 {
5323 SvxMSDffShapeTxBxSort::iterator tmpIter2 = it;
5324 --tmpIter2;
5325 SvxMSDffShapeOrder *pPrevOrder = *tmpIter2;
5326 if ((0xFFFF0000 & pOrder->nTxBxComp)
5327 == (0xFFFF0000 & pPrevOrder->nTxBxComp))
5328 pPrevFlyFormat = pPrevOrder->pFly;
5329 }
5330 // If successor or predecessor present, insert the
5331 // chain at the FlyFrame Format
5332 if (pNextFlyFormat || pPrevFlyFormat)
5333 {
5334 aChain.SetNext( pNextFlyFormat );
5335 aChain.SetPrev( pPrevFlyFormat );
5336 pFlyFormat->SetFormatAttr( aChain );
5337 }
5338 }
5339 }
5340 }
5341
5342 bool isHideRedlines(false);
5343
5344 if (m_bNewDoc)
5345 {
5346 if( m_xWDop->fRevMarking )
5347 eMode |= RedlineFlags::On;
5348 isHideRedlines = !m_xWDop->fRMView;
5349 }
5350
5351 m_aInsertedTables.DelAndMakeTableFrames();
5352 m_aSectionManager.InsertSegments();
5353
5354 m_vColl.clear();
5355
5356 m_xStyles.reset();
5357
5358 m_xFormImpl.reset();
5359 GrafikDtor();
5360 m_xMSDffManager.reset();
5361 m_xHdFt.reset();
5362 m_xSBase.reset();
5363 m_xWDop.reset();
5364 m_xFonts.reset();
5365 m_pAtnNames.reset();
5366 m_xSprmParser.reset();
5367 m_xProgress.reset();
5368
5369 m_pDataStream = nullptr;
5370 m_pTableStream = nullptr;
5371
5372 DeleteCtrlStack();
5373 DeleteAnchorStack();
5374 DeleteRefStacks();
5375 m_pLastAnchorPos.reset();//ensure this is deleted before UpdatePageDescs
5376 // ofz#10994 remove any trailing fly paras before processing redlines
5377 m_xWFlyPara.reset();
5378 // ofz#12660 remove any trailing fly paras before deleting extra paras
5379 m_xSFlyPara.reset();
5380 // remove extra paragraphs after attribute ctrl
5381 // stacks etc. are destroyed, and before fields
5382 // are updated
5383 m_aExtraneousParas.delete_all_from_doc();
5384 m_xRedlineStack->closeall(*m_pPaM->GetPoint());
5385 while (!m_aFrameRedlines.empty())
5386 m_aFrameRedlines.pop();
5387
5388 // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5389 {
5390 std::vector<const SwGrfNode*> vecBulletGrf;
5391 std::vector<SwFrameFormat*> vecFrameFormat;
5392
5393 IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
5394 if ( pMarkAccess )
5395 {
5396 IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findBookmark( "_PictureBullets" );
5397 if ( ppBkmk != pMarkAccess->getBookmarksEnd() &&
5398 IDocumentMarkAccess::GetType(**ppBkmk) == IDocumentMarkAccess::MarkType::BOOKMARK )
5399 {
5400 SwTextNode* pTextNode = (*ppBkmk)->GetMarkStart().nNode.GetNode().GetTextNode();
5401
5402 if ( pTextNode )
5403 {
5404 const SwpHints* pHints = pTextNode->GetpSwpHints();
5405 for( size_t nHintPos = 0; pHints && nHintPos < pHints->Count(); ++nHintPos)
5406 {
5407 const SwTextAttr *pHt = pHints->Get(nHintPos);
5408 if (pHt->Which() != RES_TXTATR_FLYCNT)
5409 continue;
5410 const sal_Int32 st = pHt->GetStart();
5411 if (st >= (*ppBkmk)->GetMarkStart().nContent.GetIndex())
5412 {
5413 SwFrameFormat* pFrameFormat = pHt->GetFlyCnt().GetFrameFormat();
5414 vecFrameFormat.push_back(pFrameFormat);
5415 const SwNodeIndex* pNdIdx = pFrameFormat->GetContent().GetContentIdx();
5416 const SwNodes* pNodesArray = (pNdIdx != nullptr)
5417 ? &(pNdIdx->GetNodes())
5418 : nullptr;
5419 const SwGrfNode *pGrf = (pNodesArray != nullptr)
5420 ? dynamic_cast<const SwGrfNode*>((*pNodesArray)[pNdIdx->GetIndex() + 1])
5421 : nullptr;
5422 vecBulletGrf.push_back(pGrf);
5423 }
5424 }
5425 // update graphic bullet information
5426 size_t nCount = m_xLstManager->GetWW8LSTInfoNum();
5427 for (size_t i = 0; i < nCount; ++i)
5428 {
5429 SwNumRule* pRule = m_xLstManager->GetNumRule(i);
5430 for (sal_uInt16 j = 0; j < MAXLEVEL; ++j)
5431 {
5432 SwNumFormat aNumFormat(pRule->Get(j));
5433 const sal_Int16 nType = aNumFormat.GetNumberingType();
5434 const sal_uInt16 nGrfBulletCP = aNumFormat.GetGrfBulletCP();
5435 if ( nType == SVX_NUM_BITMAP
5436 && vecBulletGrf.size() > nGrfBulletCP
5437 && vecBulletGrf[nGrfBulletCP] != nullptr )
5438 {
5439 Graphic aGraphic = vecBulletGrf[nGrfBulletCP]->GetGrf();
5440 SvxBrushItem aBrush(aGraphic, GPOS_AREA, SID_ATTR_BRUSH( 10000 + 1 ));
5441 const vcl::Font& aFont = numfunc::GetDefBulletFont();
5442 int nHeight = aFont.GetFontHeight() * 12;
5443 Size aPrefSize( aGraphic.GetPrefSize());
5444 if (aPrefSize.Height() * aPrefSize.Width() != 0 )
5445 {
5446 int nWidth = (nHeight * aPrefSize.Width()) / aPrefSize.Height();
5447 Size aSize(nWidth, nHeight);
5448 aNumFormat.SetGraphicBrush(&aBrush, &aSize);
5449 }
5450 else
5451 {
5452 aNumFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
5453 aNumFormat.SetBulletChar(0x2190);
5454 }
5455 pRule->Set( j, aNumFormat );
5456 }
5457 }
5458 }
5459 // Remove additional pictures
5460 for (SwFrameFormat* p : vecFrameFormat)
5461 {
5462 m_rDoc.getIDocumentLayoutAccess().DelLayoutFormat(p);
5463 }
5464 }
5465 }
5466 }
5467 m_xLstManager.reset();
5468 }
5469
5470 m_pPosAfterTOC.reset();
5471 m_xRedlineStack.reset();
5472 mpCursor.reset();
5473 m_pPaM = nullptr;
5474
5475 UpdateFields();
5476
5477 // delete the pam before the call for hide all redlines (Bug 73683)
5478 if (m_bNewDoc)
5479 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(eMode);
5480
5481 UpdatePageDescs(m_rDoc, nPageDescOffset);
5482
5483 // can't set it on the layout or view shell because it doesn't exist yet
5484 m_rDoc.GetDocumentRedlineManager().SetHideRedlines(isHideRedlines);
5485
5486 return ERRCODE_NONEErrCode(0);
5487}
5488
5489ErrCode SwWW8ImplReader::SetSubStreams(tools::SvRef<SotStorageStream> &rTableStream,
5490 tools::SvRef<SotStorageStream> &rDataStream)
5491{
5492 ErrCode nErrRet = ERRCODE_NONEErrCode(0);
5493 // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5494 switch (m_xWwFib->m_nVersion)
5495 {
5496 case 6:
5497 case 7:
5498 m_pTableStream = m_pStrm;
5499 m_pDataStream = m_pStrm;
5500 break;
5501 case 8:
5502 if(!m_pStg)
5503 {
5504 OSL_ENSURE( m_pStg, "Version 8 always needs to have a Storage!!" )do { if (true && (!(m_pStg))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5504" ": "), "%s", "Version 8 always needs to have a Storage!!"
); } } while (false)
;
5505 nErrRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
5506 break;
5507 }
5508
5509 rTableStream = m_pStg->OpenSotStream(
5510 m_xWwFib->m_fWhichTableStm ? SL::a1Table : SL::a0Table,
5511 StreamMode::STD_READ);
5512
5513 m_pTableStream = rTableStream.get();
5514 m_pTableStream->SetEndian( SvStreamEndian::LITTLE );
5515
5516 rDataStream = m_pStg->OpenSotStream(SL::aData, StreamMode::STD_READ);
5517
5518 if (rDataStream.is() && ERRCODE_NONEErrCode(0) == rDataStream->GetError())
5519 {
5520 m_pDataStream = rDataStream.get();
5521 m_pDataStream->SetEndian(SvStreamEndian::LITTLE);
5522 }
5523 else
5524 m_pDataStream = m_pStrm;
5525 break;
5526 default:
5527 // Program error!
5528 OSL_ENSURE( false, "We forgot to encode nVersion!" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "5528" ": "), "%s", "We forgot to encode nVersion!"); } }
while (false)
;
5529 nErrRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
5530 break;
5531 }
5532 return nErrRet;
5533}
5534
5535namespace
5536{
5537 std::unique_ptr<utl::TempFile> MakeTemp(SvFileStream &rSt)
5538 {
5539 std::unique_ptr<utl::TempFile> pT(new utl::TempFile);
5540 pT->EnableKillingFile();
5541 rSt.Open(pT->GetFileName(), StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
5542 return pT;
5543 }
5544
5545#define WW_BLOCKSIZE0x200 0x200
5546
5547 void DecryptRC4(msfilter::MSCodec97& rCtx, SvStream &rIn, SvStream &rOut)
5548 {
5549 const std::size_t nLen = rIn.TellEnd();
5550 rIn.Seek(0);
5551
5552 sal_uInt8 in[WW_BLOCKSIZE0x200];
5553 for (std::size_t nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE0x200, ++nBlock)
5554 {
5555 std::size_t nBS = std::min<size_t>(nLen - nI, WW_BLOCKSIZE0x200);
5556 nBS = rIn.ReadBytes(in, nBS);
5557 rCtx.InitCipher(nBlock);
5558 rCtx.Decode(in, nBS, in, nBS);
5559 rOut.WriteBytes(in, nBS);
5560 }
5561 }
5562
5563 void DecryptXOR(msfilter::MSCodec_XorWord95 &rCtx, SvStream &rIn, SvStream &rOut)
5564 {
5565 std::size_t nSt = rIn.Tell();
5566 std::size_t nLen = rIn.TellEnd();
5567
5568 rCtx.InitCipher();
5569 rCtx.Skip(nSt);
5570
5571 sal_uInt8 in[0x4096];
5572 for (std::size_t nI = nSt; nI < nLen; nI += 0x4096)
5573 {
5574 std::size_t nBS = std::min<size_t>(nLen - nI, 0x4096 );
5575 nBS = rIn.ReadBytes(in, nBS);
5576 rCtx.Decode(in, nBS);
5577 rOut.WriteBytes(in, nBS);
5578 }
5579 }
5580
5581 // moan, copy and paste :-(
5582 OUString QueryPasswordForMedium(SfxMedium& rMedium)
5583 {
5584 OUString aPassw;
5585
5586 const SfxItemSet* pSet = rMedium.GetItemSet();
5587 const SfxPoolItem *pPasswordItem;
5588
5589 if(pSet && SfxItemState::SET == pSet->GetItemState(SID_PASSWORD(((((10000 + 1499) + 1) + 499) + 1) + 36), true, &pPasswordItem))
5590 aPassw = static_cast<const SfxStringItem *>(pPasswordItem)->GetValue();
5591 else
5592 {
5593 try
5594 {
5595 uno::Reference< task::XInteractionHandler > xHandler( rMedium.GetInteractionHandler() );
5596 if( xHandler.is() )
5597 {
5598 ::comphelper::DocPasswordRequest* pRequest = new ::comphelper::DocPasswordRequest(
5599 ::comphelper::DocPasswordRequestType::MS, task::PasswordRequestMode_PASSWORD_ENTER,
5600 INetURLObject(rMedium.GetOrigURL())
5601 .GetLastName(INetURLObject::DecodeMechanism::WithCharset));
5602 uno::Reference< task::XInteractionRequest > xRequest( pRequest );
5603
5604 xHandler->handle( xRequest );
5605
5606 if( pRequest->isPassword() )
5607 aPassw = pRequest->getPassword();
5608 }
5609 }
5610 catch( const uno::Exception& )
5611 {
5612 }
5613 }
5614
5615 return aPassw;
5616 }
5617
5618 uno::Sequence< beans::NamedValue > InitXorWord95Codec( ::msfilter::MSCodec_XorWord95& rCodec, SfxMedium& rMedium, WW8Fib const * pWwFib )
5619 {
5620 uno::Sequence< beans::NamedValue > aEncryptionData;
5621 const SfxUnoAnyItem* pEncryptionData = SfxItemSet::GetItem<SfxUnoAnyItem>(rMedium.GetItemSet(), SID_ENCRYPTIONDATA(5000 + 1722), false);
5622 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5623 aEncryptionData.realloc( 0 );
5624
5625 if ( !aEncryptionData.hasElements() )
5626 {
5627 OUString sUniPassword = QueryPasswordForMedium( rMedium );
5628
5629 OString sPassword(OUStringToOString(sUniPassword,
5630 WW8Fib::GetFIBCharset(pWwFib->m_chseTables, pWwFib->m_lid)));
5631
5632 sal_Int32 nLen = sPassword.getLength();
5633 if( nLen <= 15 )
5634 {
5635 sal_uInt8 pPassword[16];
5636 memcpy(pPassword, sPassword.getStr(), nLen);
5637 memset(pPassword+nLen, 0, sizeof(pPassword)-nLen);
5638
5639 rCodec.InitKey( pPassword );
5640 aEncryptionData = rCodec.GetEncryptionData();
5641
5642 // the export supports RC4 algorithm only, so we have to
5643 // generate the related EncryptionData as well, so that Save
5644 // can export the document without asking for a password;
5645 // as result there will be EncryptionData for both algorithms
5646 // in the MediaDescriptor
5647 ::msfilter::MSCodec_Std97 aCodec97;
5648
5649 rtlRandomPool aRandomPool = rtl_random_createPool();
5650 sal_uInt8 pDocId[ 16 ];
5651 rtl_random_getBytes( aRandomPool, pDocId, 16 );
5652
5653 rtl_random_destroyPool( aRandomPool );
5654
5655 sal_uInt16 pStd97Pass[16] = {};
5656 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5657 pStd97Pass[nChar] = sUniPassword[nChar];
5658
5659 aCodec97.InitKey( pStd97Pass, pDocId );
5660
5661 // merge the EncryptionData, there should be no conflicts
5662 ::comphelper::SequenceAsHashMap aEncryptionHash( aEncryptionData );
5663 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
5664 aEncryptionHash >> aEncryptionData;
5665 }
5666 }
5667
5668 return aEncryptionData;
5669 }
5670
5671 uno::Sequence< beans::NamedValue > Init97Codec(msfilter::MSCodec97& rCodec, sal_uInt8 const pDocId[16], SfxMedium& rMedium)
5672 {
5673 uno::Sequence< beans::NamedValue > aEncryptionData;
5674 const SfxUnoAnyItem* pEncryptionData = SfxItemSet::GetItem<SfxUnoAnyItem>(rMedium.GetItemSet(), SID_ENCRYPTIONDATA(5000 + 1722), false);
5675 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5676 aEncryptionData.realloc( 0 );
5677
5678 if ( !aEncryptionData.hasElements() )
5679 {
5680 OUString sUniPassword = QueryPasswordForMedium( rMedium );
5681
5682 sal_Int32 nLen = sUniPassword.getLength();
5683 if ( nLen <= 15 )
5684 {
5685 sal_uInt16 pPassword[16] = {};
5686 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5687 pPassword[nChar] = sUniPassword[nChar];
5688
5689 rCodec.InitKey( pPassword, pDocId );
5690 aEncryptionData = rCodec.GetEncryptionData();
5691 }
5692 }
5693
5694 return aEncryptionData;
5695 }
5696}
5697
5698//TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5699//stream thing
5700static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo &info, SvStream &rStream)
5701{
5702 //It is possible there are other variants in existence but these
5703 //are the defaults I get with Word 2013
5704
5705 rStream.ReadUInt32(info.header.flags);
5706 if (oox::getFlag( info.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
5707 return false;
5708
5709 sal_uInt32 nHeaderSize(0);
5710 rStream.ReadUInt32(nHeaderSize);
5711 sal_uInt32 actualHeaderSize = sizeof(info.header);
5712
5713 if (nHeaderSize < actualHeaderSize)
5714 return false;
5715
5716 rStream.ReadUInt32(info.header.flags);
5717 rStream.ReadUInt32(info.header.sizeExtra);
5718 rStream.ReadUInt32(info.header.algId);
5719 rStream.ReadUInt32(info.header.algIdHash);
5720 rStream.ReadUInt32(info.header.keyBits);
5721 rStream.ReadUInt32(info.header.providedType);
5722 rStream.ReadUInt32(info.header.reserved1);
5723 rStream.ReadUInt32(info.header.reserved2);
5724
5725 rStream.SeekRel(nHeaderSize - actualHeaderSize);
5726
5727 rStream.ReadUInt32(info.verifier.saltSize);
5728 if (info.verifier.saltSize != msfilter::SALT_LENGTH)
5729 return false;
5730 rStream.ReadBytes(&info.verifier.salt, sizeof(info.verifier.salt));
5731 rStream.ReadBytes(&info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier));
5732
5733 rStream.ReadUInt32(info.verifier.encryptedVerifierHashSize);
5734 if (info.verifier.encryptedVerifierHashSize != RTL_DIGEST_LENGTH_SHA120)
5735 return false;
5736 rStream.ReadBytes(&info.verifier.encryptedVerifierHash, info.verifier.encryptedVerifierHashSize);
5737
5738 // check flags and algorithm IDs, required are AES128 and SHA-1
5739 if (!oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
5740 return false;
5741
5742 if (oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_AES))
5743 return false;
5744
5745 if (info.header.algId != msfilter::ENCRYPT_ALGO_RC4)
5746 return false;
5747
5748 // hash algorithm ID 0 defaults to SHA-1 too
5749 if (info.header.algIdHash != 0 && info.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
5750 return false;
5751
5752 return true;
5753}
5754
5755ErrCode SwWW8ImplReader::LoadThroughDecryption(WW8Glossary *pGloss)
5756{
5757 ErrCode nErrRet = ERRCODE_NONEErrCode(0);
5758 if (pGloss)
5759 m_xWwFib = pGloss->GetFib();
5760 else
5761 m_xWwFib = std::make_shared<WW8Fib>(*m_pStrm, m_nWantedVersion);
5762
5763 if (m_xWwFib->m_nFibError)
5764 nErrRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
5765
5766 tools::SvRef<SotStorageStream> xTableStream, xDataStream;
5767
5768 if (!nErrRet)
5769 nErrRet = SetSubStreams(xTableStream, xDataStream);
5770
5771 std::unique_ptr<utl::TempFile> pTempMain;
5772 std::unique_ptr<utl::TempFile> pTempTable;
5773 std::unique_ptr<utl::TempFile> pTempData;
5774 SvFileStream aDecryptMain;
5775 SvFileStream aDecryptTable;
5776 SvFileStream aDecryptData;
5777
5778 bool bDecrypt = false;
5779 enum {RC4CryptoAPI, RC4, XOR, Other} eAlgo = Other;
5780 if (m_xWwFib->m_fEncrypted && !nErrRet)
5781 {
5782 if (!pGloss)
5783 {
5784 bDecrypt = true;
5785 if (8 != m_xWwFib->m_nVersion)
5786 eAlgo = XOR;
5787 else
5788 {
5789 if (m_xWwFib->m_nKey != 0)
5790 eAlgo = XOR;
5791 else
5792 {
5793 m_pTableStream->Seek(0);
5794 sal_uInt32 nEncType(0);
5795 m_pTableStream->ReadUInt32(nEncType);
5796 if (nEncType == msfilter::VERSION_INFO_1997_FORMAT)
5797 eAlgo = RC4;
5798 else if (nEncType == msfilter::VERSION_INFO_2007_FORMAT || nEncType == msfilter::VERSION_INFO_2007_FORMAT_SP2)
5799 eAlgo = RC4CryptoAPI;
5800 }
5801 }
5802 }
5803 }
5804
5805 if (bDecrypt)
5806 {
5807 nErrRet = ERRCODE_SVX_WRONGPASSErrCode( ErrCodeArea::Svx, ErrCodeClass::NONE, 15);
5808 SfxMedium* pMedium = m_pDocShell->GetMedium();
5809
5810 if ( pMedium )
5811 {
5812 switch (eAlgo)
5813 {
5814 default:
5815 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPTErrCode( ErrCodeArea::Svx, ErrCodeClass::Read, 16);
5816 break;
5817 case XOR:
5818 {
5819 msfilter::MSCodec_XorWord95 aCtx;
5820 uno::Sequence< beans::NamedValue > aEncryptionData = InitXorWord95Codec(aCtx, *pMedium, m_xWwFib.get());
5821
5822 // if initialization has failed the EncryptionData should be empty
5823 if (aEncryptionData.hasElements() && aCtx.VerifyKey(m_xWwFib->m_nKey, m_xWwFib->m_nHash))
5824 {
5825 nErrRet = ERRCODE_NONEErrCode(0);
5826 pTempMain = MakeTemp(aDecryptMain);
5827
5828 m_pStrm->Seek(0);
5829 size_t nUnencryptedHdr =
5830 (8 == m_xWwFib->m_nVersion) ? 0x44 : 0x34;
5831 std::unique_ptr<sal_uInt8[]> pIn(new sal_uInt8[nUnencryptedHdr]);
5832 nUnencryptedHdr = m_pStrm->ReadBytes(pIn.get(), nUnencryptedHdr);
5833 aDecryptMain.WriteBytes(pIn.get(), nUnencryptedHdr);
5834 pIn.reset();
5835
5836 DecryptXOR(aCtx, *m_pStrm, aDecryptMain);
5837
5838 if (!m_pTableStream || m_pTableStream == m_pStrm)
5839 m_pTableStream = &aDecryptMain;
5840 else
5841 {
5842 pTempTable = MakeTemp(aDecryptTable);
5843 DecryptXOR(aCtx, *m_pTableStream, aDecryptTable);
5844 m_pTableStream = &aDecryptTable;
5845 }
5846
5847 if (!m_pDataStream || m_pDataStream == m_pStrm)
5848 m_pDataStream = &aDecryptMain;
5849 else
5850 {
5851 pTempData = MakeTemp(aDecryptData);
5852 DecryptXOR(aCtx, *m_pDataStream, aDecryptData);
5853 m_pDataStream = &aDecryptData;
5854 }
5855
5856 pMedium->GetItemSet()->ClearItem( SID_PASSWORD(((((10000 + 1499) + 1) + 499) + 1) + 36) );
5857 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA(5000 + 1722), uno::makeAny( aEncryptionData ) ) );
5858 }
5859 }
5860 break;
5861 case RC4:
5862 case RC4CryptoAPI:
5863 {
5864 std::unique_ptr<msfilter::MSCodec97> xCtx;
5865 msfilter::RC4EncryptionInfo info;
5866 bool bCouldReadHeaders;
5867
5868 if (eAlgo == RC4)
5869 {
5870 xCtx.reset(new msfilter::MSCodec_Std97);
5871 assert(sizeof(info.verifier.encryptedVerifierHash) >= RTL_DIGEST_LENGTH_MD5)(static_cast <bool> (sizeof(info.verifier.encryptedVerifierHash
) >= 16) ? void (0) : __assert_fail ("sizeof(info.verifier.encryptedVerifierHash) >= RTL_DIGEST_LENGTH_MD5"
, "/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
, 5871, __extension__ __PRETTY_FUNCTION__))
;
5872 bCouldReadHeaders =
5873 checkRead(*m_pTableStream, info.verifier.salt, sizeof(info.verifier.salt)) &&
5874 checkRead(*m_pTableStream, info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier)) &&
5875 checkRead(*m_pTableStream, info.verifier.encryptedVerifierHash, RTL_DIGEST_LENGTH_MD516);
5876 }
5877 else
5878 {
5879 xCtx.reset(new msfilter::MSCodec_CryptoAPI);
5880 bCouldReadHeaders = lclReadCryptoAPIHeader(info, *m_pTableStream);
5881 }
5882
5883 // if initialization has failed the EncryptionData should be empty
5884 uno::Sequence< beans::NamedValue > aEncryptionData;
5885 if (bCouldReadHeaders)
5886 aEncryptionData = Init97Codec(*xCtx, info.verifier.salt, *pMedium);
5887 else
5888 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPTErrCode( ErrCodeArea::Svx, ErrCodeClass::Read, 16);
5889 if (aEncryptionData.hasElements() && xCtx->VerifyKey(info.verifier.encryptedVerifier,
5890 info.verifier.encryptedVerifierHash))
5891 {
5892 nErrRet = ERRCODE_NONEErrCode(0);
5893
5894 pTempMain = MakeTemp(aDecryptMain);
5895
5896 m_pStrm->Seek(0);
5897 std::size_t nUnencryptedHdr = 0x44;
5898 std::unique_ptr<sal_uInt8[]> pIn(new sal_uInt8[nUnencryptedHdr]);
5899 nUnencryptedHdr = m_pStrm->ReadBytes(pIn.get(), nUnencryptedHdr);
5900
5901 DecryptRC4(*xCtx, *m_pStrm, aDecryptMain);
5902
5903 aDecryptMain.Seek(0);
5904 aDecryptMain.WriteBytes(pIn.get(), nUnencryptedHdr);
5905 pIn.reset();
5906
5907 pTempTable = MakeTemp(aDecryptTable);
5908 DecryptRC4(*xCtx, *m_pTableStream, aDecryptTable);
5909 m_pTableStream = &aDecryptTable;
5910
5911 if (!m_pDataStream || m_pDataStream == m_pStrm)
5912 m_pDataStream = &aDecryptMain;
5913 else
5914 {
5915 pTempData = MakeTemp(aDecryptData);
5916 DecryptRC4(*xCtx, *m_pDataStream, aDecryptData);
5917 m_pDataStream = &aDecryptData;
5918 }
5919
5920 pMedium->GetItemSet()->ClearItem( SID_PASSWORD(((((10000 + 1499) + 1) + 499) + 1) + 36) );
5921 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA(5000 + 1722), uno::makeAny( aEncryptionData ) ) );
5922 }
5923 }
5924 break;
5925 }
5926 }
5927
5928 if (nErrRet == ERRCODE_NONEErrCode(0))
5929 {
5930 m_pStrm = &aDecryptMain;
5931
5932 m_xWwFib = std::make_shared<WW8Fib>(*m_pStrm, m_nWantedVersion);
5933 if (m_xWwFib->m_nFibError)
5934 nErrRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
5935 }
5936 }
5937
5938 if (!nErrRet)
5939 nErrRet = CoreLoad(pGloss);
5940
5941 pTempMain.reset();
5942 pTempTable.reset();
5943 pTempData.reset();
5944
5945 m_xWwFib.reset();
5946 return nErrRet;
5947}
5948
5949void SwWW8ImplReader::SetOutlineStyles()
5950{
5951 // If we are inserted into a document then don't clobber existing outline
5952 // levels.
5953 sal_uInt16 nOutlineStyleListLevelWithAssignment = 0;
5954 if (!m_bNewDoc)
5955 {
5956 ww8::ParaStyles aOutLined(sw::util::GetParaStyles(m_rDoc));
5957 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined);
5958 ww8::ParaStyles::reverse_iterator aEnd = aOutLined.rend();
5959 for ( ww8::ParaStyles::reverse_iterator aIter = aOutLined.rbegin(); aIter < aEnd; ++aIter)
5960 {
5961 if ((*aIter)->IsAssignedToListLevelOfOutlineStyle())
5962 nOutlineStyleListLevelWithAssignment |= 1 << (*aIter)->GetAssignedOutlineStyleLevel();
5963 else
5964 break;
5965 }
5966 }
5967
5968 // Check applied WW8 list styles at WW8 Built-In Heading Styles
5969 // - Choose the list style which occurs most often as the one which provides
5970 // the list level properties for the Outline Style.
5971 // - Populate temporary list of WW8 Built-In Heading Styles for further
5972 // iteration
5973 std::vector<SwWW8StyInf*> aWW8BuiltInHeadingStyles;
5974 const SwNumRule* pChosenWW8ListStyle = nullptr;
5975 {
5976 std::map<const SwNumRule*, int> aWW8ListStyleCounts;
5977 for (SwWW8StyInf & rSI : m_vColl)
5978 {
5979 if (!rSI.IsWW8BuiltInHeadingStyle() || !rSI.HasWW8OutlineLevel())
5980 {
5981 continue;
5982 }
5983
5984 aWW8BuiltInHeadingStyles.push_back(&rSI);
5985
5986 const SwNumRule* pWW8ListStyle = rSI.GetOutlineNumrule();
5987 if (pWW8ListStyle != nullptr)
5988 {
5989 std::map<const SwNumRule*, int>::iterator aCountIter
5990 = aWW8ListStyleCounts.find(pWW8ListStyle);
5991 if (aCountIter == aWW8ListStyleCounts.end())
5992 {
5993 aWW8ListStyleCounts[pWW8ListStyle] = 1;
5994 }
5995 else
5996 {
5997 ++(aCountIter->second);
5998 }
5999 }
6000 }
6001
6002 int nCurrentMaxCount = 0;
6003 for (const auto& rEntry : aWW8ListStyleCounts)
6004 {
6005 if (rEntry.second > nCurrentMaxCount)
6006 {
6007 nCurrentMaxCount = rEntry.second;
6008 pChosenWW8ListStyle = rEntry.first;
6009 }
6010 }
6011 }
6012
6013 // - set list level properties of Outline Style - ODF's list style applied
6014 // by default to headings
6015 // - assign corresponding Heading Paragraph Styles to the Outline Style
6016 // - If a heading Paragraph Styles is not applying the WW8 list style which
6017 // had been chosen as
6018 // the one which provides the list level properties for the Outline Style,
6019 // its assignment to
6020 // the Outline Style is removed. A potential applied WW8 list style is
6021 // assigned directly and
6022 // its default outline level is applied.
6023 SwNumRule aOutlineRule(*m_rDoc.GetOutlineNumRule());
6024 bool bAppliedChangedOutlineStyle = false;
6025 for (const SwWW8StyInf* pStyleInf : aWW8BuiltInHeadingStyles)
6026 {
6027 if (!pStyleInf->m_bColl) //Character Style
6028 continue;
6029
6030 const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6031 = 1 << pStyleInf->mnWW8OutlineLevel;
6032 if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6033 & nOutlineStyleListLevelWithAssignment)
6034 {
6035 continue;
6036 }
6037
6038 if (pChosenWW8ListStyle != nullptr && pStyleInf->mnWW8OutlineLevel
6039 == pStyleInf->m_nListLevel)
6040 {
6041 const SwNumFormat& rRule
6042 = pChosenWW8ListStyle->Get(pStyleInf->mnWW8OutlineLevel);
6043 aOutlineRule.Set(pStyleInf->mnWW8OutlineLevel, rRule);
6044 bAppliedChangedOutlineStyle = true;
6045 }
6046
6047 // in case that there are more styles on this level ignore them
6048 nOutlineStyleListLevelWithAssignment
6049 |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle;
6050
6051 SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pStyleInf->m_pFormat);
6052 if (pStyleInf->GetOutlineNumrule() != pChosenWW8ListStyle
6053 || (pStyleInf->m_nListLevel < WW8ListManager::nMaxLevel
6054 && pStyleInf->mnWW8OutlineLevel != pStyleInf->m_nListLevel))
6055 {
6056 // WW8 Built-In Heading Style does not apply the chosen one.
6057 // --> delete assignment to OutlineStyle, but keep its current
6058 // outline level
6059 pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
6060 // Apply existing WW8 list style a normal list style at the
6061 // Paragraph Style
6062 if (pStyleInf->GetOutlineNumrule() != nullptr)
6063 {
6064 pTextFormatColl->SetFormatAttr(
6065 SwNumRuleItem(pStyleInf->GetOutlineNumrule()->GetName()));
6066 }
6067 // apply default outline level of WW8 Built-in Heading Style
6068 const sal_uInt8 nOutlineLevel
6069 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6070 pStyleInf->mnWW8OutlineLevel);
6071 pTextFormatColl->SetFormatAttr(
6072 SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
6073 }
6074 else
6075 {
6076 pTextFormatColl->AssignToListLevelOfOutlineStyle(
6077 pStyleInf->mnWW8OutlineLevel);
6078 }
6079 }
6080
6081 if (bAppliedChangedOutlineStyle)
6082 {
6083 m_rDoc.SetOutlineNumRule(aOutlineRule);
6084 }
6085}
6086
6087const OUString* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx)
6088{
6089 if (!m_pAtnNames && m_xWwFib->m_lcbGrpStAtnOwners)
6090 {
6091 // Determine authors: can be found in the TableStream
6092 m_pAtnNames.reset(new std::vector<OUString>);
6093 SvStream& rStrm = *m_pTableStream;
6094
6095 long nOldPos = rStrm.Tell();
6096 rStrm.Seek( m_xWwFib->m_fcGrpStAtnOwners );
6097
6098 long nRead = 0, nCount = m_xWwFib->m_lcbGrpStAtnOwners;
6099 while (nRead < nCount && rStrm.good())
6100 {
6101 if( m_bVer67 )
6102 {
6103 m_pAtnNames->push_back(read_uInt8_PascalString(rStrm,
6104 RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1))));
6105 nRead += m_pAtnNames->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6106 }
6107 else
6108 {
6109 m_pAtnNames->push_back(read_uInt16_PascalString(rStrm));
6110 // Unicode: double the length + sal_uInt16 count
6111 nRead += (m_pAtnNames->rbegin()->getLength() + 1)*2;
6112 }
6113 }
6114 rStrm.Seek( nOldPos );
6115 }
6116
6117 const OUString *pRet = nullptr;
6118 if (m_pAtnNames && nIdx < m_pAtnNames->size())
6119 pRet = &((*m_pAtnNames)[nIdx]);
6120 return pRet;
6121}
6122
6123void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark& rMark)
6124{
6125 if (!m_pSmartTagData && m_xWwFib->m_lcbFactoidData)
6126 {
6127 m_pSmartTagData.reset(new WW8SmartTagData);
6128 m_pSmartTagData->Read(*m_pTableStream, m_xWwFib->m_fcFactoidData, m_xWwFib->m_lcbFactoidData);
6129 }
6130
6131 if (!m_pSmartTagData)
6132 return;
6133
6134 // Check if the handle is a valid smart tag bookmark index.
6135 size_t nIndex = rMark.GetHandle();
6136 if (nIndex >= m_pSmartTagData->m_aPropBags.size())
6137 return;
6138
6139 // Check if the smart tag bookmark refers to a valid factoid type.
6140 const MSOPropertyBag& rPropertyBag = m_pSmartTagData->m_aPropBags[rMark.GetHandle()];
6141 auto& rFactoidTypes = m_pSmartTagData->m_aPropBagStore.m_aFactoidTypes;
6142 auto itPropertyBag = std::find_if(rFactoidTypes.begin(), rFactoidTypes.end(),
6143 [&rPropertyBag](const MSOFactoidType& rType) { return rType.m_nId == rPropertyBag.m_nId; });
6144 if (itPropertyBag == rFactoidTypes.end())
6145 return;
6146
6147 // Check if the factoid is an RDF one.
6148 const MSOFactoidType& rFactoidType = *itPropertyBag;
6149 if (rFactoidType.m_aUri != "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6150 return;
6151
6152 // Finally put the relevant attributes to the mark.
6153 std::vector< std::pair<OUString, OUString> > aAttributes;
6154 for (const MSOProperty& rProperty : rPropertyBag.m_aProperties)
6155 {
6156 OUString aKey;
6157 OUString aValue;
6158 if (rProperty.m_nKey < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6159 aKey = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nKey];
6160 if (rProperty.m_nValue < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6161 aValue = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nValue];
6162 if (!aKey.isEmpty() && !aValue.isEmpty())
6163 aAttributes.emplace_back(aKey, aValue);
6164 }
6165 rMark.SetAttributes(aAttributes);
6166}
6167
6168ErrCode SwWW8ImplReader::LoadDoc(WW8Glossary *pGloss)
6169{
6170 ErrCode nErrRet = ERRCODE_NONEErrCode(0);
6171
6172 {
6173 static const char* aNames[ 13 ] = {
6174 "WinWord/WW", "WinWord/WW8", "WinWord/WWFT",
6175 "WinWord/WWFLX", "WinWord/WWFLY",
6176 "WinWord/WWF",
6177 "WinWord/WWFA0", "WinWord/WWFA1", "WinWord/WWFA2",
6178 "WinWord/WWFB0", "WinWord/WWFB1", "WinWord/WWFB2",
6179 "WinWord/RegardHindiDigits"
6180 };
6181 sal_uInt64 aVal[ 13 ];
6182
6183 SwFilterOptions aOpt( 13, aNames, aVal );
6184
6185 m_nIniFlags = aVal[ 0 ];
6186 m_nIniFlags1= aVal[ 1 ];
6187 // Moves Flys by x twips to the right or left
6188 m_nIniFlyDx = aVal[ 3 ];
6189 m_nIniFlyDy = aVal[ 4 ];
6190
6191 m_nFieldFlags = aVal[ 5 ];
6192 m_nFieldTagAlways[0] = aVal[ 6 ];
6193 m_nFieldTagAlways[1] = aVal[ 7 ];
6194 m_nFieldTagAlways[2] = aVal[ 8 ];
6195 m_nFieldTagBad[0] = aVal[ 9 ];
6196 m_nFieldTagBad[1] = aVal[ 10 ];
6197 m_nFieldTagBad[2] = aVal[ 11 ];
6198 m_bRegardHindiDigits = aVal[ 12 ] > 0;
6199 }
6200
6201 sal_uInt16 nMagic(0);
6202 m_pStrm->ReadUInt16( nMagic );
6203
6204 // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6205 switch (m_nWantedVersion)
6206 {
6207 case 6:
6208 case 7:
6209 if (
6210 0xa59b != nMagic && 0xa59c != nMagic &&
6211 0xa5dc != nMagic && 0xa5db != nMagic &&
6212 (nMagic < 0xa697 || nMagic > 0xa699)
6213 )
6214 {
6215 // Test for own 97 fake!
6216 if (m_pStg && 0xa5ec == nMagic)
6217 {
6218 sal_uLong nCurPos = m_pStrm->Tell();
6219 if (m_pStrm->Seek(nCurPos + 22))
6220 {
6221 sal_uInt32 nfcMin;
6222 m_pStrm->ReadUInt32( nfcMin );
6223 if (0x300 != nfcMin)
6224 nErrRet = ERR_WW6_NO_WW6_FILE_ERRErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 8 );
6225 }
6226 m_pStrm->Seek( nCurPos );
6227 }
6228 else
6229 nErrRet = ERR_WW6_NO_WW6_FILE_ERRErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 8 );
6230 }
6231 break;
6232 case 8:
6233 if (0xa5ec != nMagic)
6234 nErrRet = ERR_WW8_NO_WW8_FILE_ERRErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 14);
6235 break;
6236 default:
6237 nErrRet = ERR_WW8_NO_WW8_FILE_ERRErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 14);
6238 OSL_ENSURE( false, "We forgot to encode nVersion!" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "6238" ": "), "%s", "We forgot to encode nVersion!"); } }
while (false)
;
6239 break;
6240 }
6241
6242 if (!nErrRet)
6243 nErrRet = LoadThroughDecryption(pGloss);
6244
6245 m_rDoc.PropagateOutlineRule();
6246
6247 return nErrRet;
6248}
6249
6250extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) Reader* ImportDOC()
6251{
6252 return new WW8Reader;
6253}
6254
6255namespace
6256{
6257 class FontCacheGuard
6258 {
6259 public:
6260 ~FontCacheGuard()
6261 {
6262 FlushFontCache();
6263 }
6264 };
6265}
6266
6267bool TestImportDOC(SvStream &rStream, const OUString &rFltName)
6268{
6269 FontCacheGuard aFontCacheGuard;
6270 std::unique_ptr<Reader> xReader(ImportDOC());
6271
6272 tools::SvRef<SotStorage> xStorage;
6273 xReader->m_pStream = &rStream;
6274 if (rFltName != "WW6")
2
Taking true branch
6275 {
6276 try
6277 {
6278 xStorage = tools::SvRef<SotStorage>(new SotStorage(rStream));
3
Memory is allocated
6279 if (xStorage->GetError())
4
Taking true branch
6280 return false;
6281 }
6282 catch (...)
6283 {
6284 return false;
6285 }
6286 xReader->m_pStorage = xStorage.get();
6287 }
6288 xReader->SetFltName(rFltName);
6289
6290 SwGlobals::ensure();
6291
6292 SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
6293 xDocSh->DoInitNew();
6294 SwDoc *pD = static_cast<SwDocShell*>((&xDocSh))->GetDoc();
6295
6296 SwNodeIndex aIdx(pD->GetNodes().GetEndOfContent(), -1);
6297 SwPaM aPaM(aIdx);
6298 aPaM.GetPoint()->nContent.Assign(aIdx.GetNode().GetContentNode(), 0);
6299 pD->SetInReading(true);
6300 bool bRet = xReader->Read(*pD, OUString(), aPaM, OUString()) == ERRCODE_NONEErrCode(0);
6301 pD->SetInReading(false);
6302
6303 return bRet;
6304}
5
Potential leak of memory pointed to by 'xStorage.pObj'
6305
6306extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool TestImportWW8(SvStream &rStream)
6307{
6308 return TestImportDOC(rStream, "CWW8");
6309}
6310
6311extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool TestImportWW6(SvStream &rStream)
6312{
6313 return TestImportDOC(rStream, "CWW6");
6314}
6315
6316extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool TestImportWW2(SvStream &rStream)
6317{
6318 return TestImportDOC(rStream, "WW6");
1
Calling 'TestImportDOC'
6319}
6320
6321ErrCode WW8Reader::OpenMainStream( tools::SvRef<SotStorageStream>& rRef, sal_uInt16& rBuffSize )
6322{
6323 ErrCode nRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
6324 OSL_ENSURE(m_pStorage, "Where is my Storage?")do { if (true && (!(m_pStorage))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "6324" ": "), "%s", "Where is my Storage?"); } } while (
false)
;
6325 rRef = m_pStorage->OpenSotStream( "WordDocument", StreamMode::READ | StreamMode::SHARE_DENYALL);
6326
6327 if( rRef.is() )
6328 {
6329 if( ERRCODE_NONEErrCode(0) == rRef->GetError() )
6330 {
6331 sal_uInt16 nOld = rRef->GetBufferSize();
6332 rRef->SetBufferSize( rBuffSize );
6333 rBuffSize = nOld;
6334 nRet = ERRCODE_NONEErrCode(0);
6335 }
6336 else
6337 nRet = rRef->GetError();
6338 }
6339 return nRet;
6340}
6341
6342static void lcl_getListOfStreams(SotStorage * pStorage, comphelper::SequenceAsHashMap& aStreamsData, const OUString& sPrefix)
6343{
6344 SvStorageInfoList aElements;
6345 pStorage->FillInfoList(&aElements);
6346 for (const auto & aElement : aElements)
6347 {
6348 OUString sStreamFullName = sPrefix.getLength() ? sPrefix + "/" + aElement.GetName() : aElement.GetName();
6349 if (aElement.IsStorage())
6350 {
6351 tools::SvRef<SotStorage> xSubStorage = pStorage->OpenSotStorage(aElement.GetName(), StreamMode::STD_READ | StreamMode::SHARE_DENYALL);
6352 lcl_getListOfStreams(xSubStorage.get(), aStreamsData, sStreamFullName);
6353 }
6354 else
6355 {
6356 // Read stream
6357 tools::SvRef<SotStorageStream> rStream = pStorage->OpenSotStream(aElement.GetName(), StreamMode::READ | StreamMode::SHARE_DENYALL);
6358 if (rStream.is())
6359 {
6360 sal_Int32 nStreamSize = rStream->GetSize();
6361 css::uno::Sequence< sal_Int8 > oData;
6362 oData.realloc(nStreamSize);
6363 sal_Int32 nReadBytes = rStream->ReadBytes(oData.getArray(), nStreamSize);
6364 if (nStreamSize == nReadBytes)
6365 aStreamsData[sStreamFullName] <<= oData;
6366 }
6367 }
6368 }
6369}
6370
6371ErrCode WW8Reader::DecryptDRMPackage()
6372{
6373 // We have DRM encrypted storage. We should try to decrypt it first, if we can
6374 uno::Sequence< uno::Any > aArguments;
6375 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
6376 uno::Reference< packages::XPackageEncryption > xPackageEncryption(
6377 xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
6378 "com.sun.star.comp.oox.crypto.DRMDataSpace", aArguments, xComponentContext), uno::UNO_QUERY);
6379
6380 if (!xPackageEncryption.is())
6381 {
6382 // We do not know how to decrypt this
6383 return ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 );
6384 }
6385
6386 comphelper::SequenceAsHashMap aStreamsData;
6387 lcl_getListOfStreams(m_pStorage.get(), aStreamsData, "");
6388
6389 try {
6390 uno::Sequence<beans::NamedValue> aStreams = aStreamsData.getAsConstNamedValueList();
6391 if (!xPackageEncryption->readEncryptionInfo(aStreams))
6392 {
6393 // We failed with decryption
6394 return ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 );
6395 }
6396
6397 tools::SvRef<SotStorageStream> rContentStream = m_pStorage->OpenSotStream("\011DRMContent", StreamMode::READ | StreamMode::SHARE_DENYALL);
6398 if (!rContentStream.is())
6399 {
6400 return ERRCODE_IO_NOTEXISTSErrCode( ErrCodeArea::Io, ErrCodeClass::NotExists, 2 );
6401 }
6402
6403 mDecodedStream = std::make_shared<SvMemoryStream>();
6404
6405 uno::Reference<io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream.get(), false));
6406 uno::Reference<io::XOutputStream > xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*mDecodedStream));
6407
6408 if (!xPackageEncryption->decrypt(xInputStream, xDecryptedStream))
6409 {
6410 // We failed with decryption
6411 return ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 );
6412 }
6413
6414 mDecodedStream->Seek(0);
6415
6416 // Further reading is done from new document
6417 m_pStorage = new SotStorage(*mDecodedStream);
6418
6419 // Set the media descriptor data
6420 uno::Sequence<beans::NamedValue> aEncryptionData = xPackageEncryption->createEncryptionData("");
6421 m_pMedium->GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA(5000 + 1722), uno::makeAny(aEncryptionData)));
6422 }
6423 catch (const std::exception&)
6424 {
6425 return ERRCODE_IO_ACCESSDENIEDErrCode( ErrCodeArea::Io, ErrCodeClass::Access, 7 );
6426 }
6427
6428 return ERRCODE_NONEErrCode(0);
6429}
6430
6431ErrCode WW8Reader::Read(SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, const OUString & /* FileName */)
6432{
6433 sal_uInt16 nOldBuffSize = 32768;
6434 bool bNew = !m_bInsertMode; // New Doc (no inserting)
6435
6436 tools::SvRef<SotStorageStream> refStrm; // So that no one else can steal the Stream
6437 SvStream* pIn = m_pStream;
6438
6439 ErrCode nRet = ERRCODE_NONEErrCode(0);
6440 sal_uInt8 nVersion = 8;
6441
6442 const OUString sFltName = GetFltName();
6443 if ( sFltName=="WW6" )
6444 {
6445 if (m_pStream)
6446 nVersion = 6;
6447 else
6448 {
6449 OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "6449" ": "), "%s", "WinWord 95 Reader-Read without Stream"
); } } while (false)
;
6450 nRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
6451 }
6452 }
6453 else
6454 {
6455 if ( sFltName=="CWW6" )
6456 nVersion = 6;
6457 else if ( sFltName=="CWW7" )
6458 nVersion = 7;
6459
6460 if( m_pStorage.is() )
6461 {
6462 // Check if we have special encrypted content
6463 tools::SvRef<SotStorageStream> rRef = m_pStorage->OpenSotStream("\006DataSpaces/DataSpaceInfo/\011DRMDataSpace", StreamMode::READ | StreamMode::SHARE_DENYALL);
6464 if (rRef.is())
6465 {
6466 nRet = DecryptDRMPackage();
6467 }
6468 nRet = OpenMainStream(refStrm, nOldBuffSize);
6469 pIn = refStrm.get();
6470 }
6471 else
6472 {
6473 OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/filter/ww8/ww8par.cxx"
":" "6473" ": "), "%s", "WinWord 95/97 Reader-Read without Storage"
); } } while (false)
;
6474 nRet = ERR_SWG_READ_ERRORErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 2 );
6475 }
6476 }
6477
6478 if( !nRet )
6479 {
6480 std::unique_ptr<SwWW8ImplReader> pRdr(new SwWW8ImplReader(nVersion, m_pStorage.get(), pIn, rDoc,
6481 rBaseURL, bNew, m_bSkipImages, *rPaM.GetPoint()));
6482 if (bNew)
6483 {
6484 rPaM.GetBound().nContent.Assign(nullptr, 0);
6485 rPaM.GetBound(false).nContent.Assign(nullptr, 0);
6486 }
6487 try
6488 {
6489 nRet = pRdr->LoadDoc();
6490 }
6491 catch( const std::exception& )
6492 {
6493 nRet = ERR_WW8_NO_WW8_FILE_ERRErrCode(ErrCodeArea::Sw, ErrCodeClass::Read, 14);
6494 }
6495
6496 if( refStrm.is() )
6497 {
6498 refStrm->SetBufferSize( nOldBuffSize );
6499 refStrm.clear();
6500 }
6501 else
6502 {
6503 pIn->ResetError();
6504 }
6505
6506 }
6507 return nRet;
6508}
6509
6510SwReaderType WW8Reader::GetReaderType()
6511{
6512 return SwReaderType::Storage | SwReaderType::Stream;
6513}
6514
6515bool WW8Reader::HasGlossaries() const
6516{
6517 return true;
6518}
6519
6520bool WW8Reader::ReadGlossaries(SwTextBlocks& rBlocks, bool bSaveRelFiles) const
6521{
6522 bool bRet=false;
6523
6524 WW8Reader *pThis = const_cast<WW8Reader *>(this);
6525
6526 sal_uInt16 nOldBuffSize = 32768;
6527 tools::SvRef<SotStorageStream> refStrm;
6528 if (!pThis->OpenMainStream(refStrm, nOldBuffSize))
6529 {
6530 WW8Glossary aGloss( refStrm, 8, m_pStorage.get() );
6531 bRet = aGloss.Load( rBlocks, bSaveRelFiles );
6532 }
6533 return bRet;
6534}
6535
6536bool SwMSDffManager::GetOLEStorageName(sal_uInt32 nOLEId, OUString& rStorageName,
6537 tools::SvRef<SotStorage>& rSrcStorage, uno::Reference < embed::XStorage >& rDestStorage) const
6538{
6539 bool bRet = false;
6540
6541 sal_Int32 nPictureId = 0;
6542 if (rReader.m_pStg)
6543 {
6544 // Via the TextBox-PLCF we get the right char Start-End positions
6545 // We should then find the EmbeddedField and the corresponding Sprms
6546 // in that Area.
6547 // We only need the Sprm for the Picture Id.
6548 long nOldPos = rReader.m_pStrm->Tell();
6549 {
6550 // #i32596# - consider return value of method
6551 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6552 // wasn't successful. Thus, continue in this case.
6553 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6554 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6555 WW8_CP nStartCp, nEndCp;
6556 if ( rReader.m_bDrawCpOValid && rReader.GetTxbxTextSttEndCp(nStartCp, nEndCp,
6557 static_cast<sal_uInt16>((nOLEId >> 16) & 0xFFFF),
6558 static_cast<sal_uInt16>(nOLEId & 0xFFFF)) )
6559 {
6560 WW8PLCFxSaveAll aSave;
6561 rReader.m_xPlcxMan->SaveAllPLCFx( aSave );
6562
6563 nStartCp += rReader.m_nDrawCpO;
6564 nEndCp += rReader.m_nDrawCpO;
6565 WW8PLCFx_Cp_FKP* pChp = rReader.m_xPlcxMan->GetChpPLCF();
6566 wwSprmParser aSprmParser(*rReader.m_xWwFib);
6567 while (nStartCp <= nEndCp && !nPictureId)
6568 {
6569 if (!pChp->SeekPos( nStartCp))
6570 break;
6571 WW8PLCFxDesc aDesc;
6572 pChp->GetSprms( &aDesc );
6573
6574 if (aDesc.nSprmsLen && aDesc.pMemPos) // Attributes present
6575 {
6576 auto nLen = aDesc.nSprmsLen;
6577 const sal_uInt8* pSprm = aDesc.pMemPos;
6578
6579 while (nLen >= 2 && !nPictureId)
6580 {
6581 sal_uInt16 nId = aSprmParser.GetSprmId(pSprm);
6582 sal_Int32 nSL = aSprmParser.GetSprmSize(nId, pSprm, nLen);
6583
6584 if( nLen < nSL )
6585 break; // Not enough Bytes left
6586
6587 if (0x6A03 == nId)
6588 {
6589 nPictureId = SVBT32ToUInt32(pSprm +
6590 aSprmParser.DistanceToData(nId));
6591 bRet = true;
6592 }
6593 pSprm += nSL;
6594 nLen -= nSL;
6595 }
6596 }
6597 nStartCp = aDesc.nEndPos;
6598 }
6599
6600 rReader.m_xPlcxMan->RestoreAllPLCFx( aSave );
6601 }
6602 }
6603 rReader.m_pStrm->Seek( nOldPos );
6604 }
6605
6606 if( bRet )
6607 {
6608 rStorageName = "_";
6609 rStorageName += OUString::number(nPictureId);
6610 rSrcStorage = rReader.m_pStg->OpenSotStorage(SL::aObjectPool);
6611 if (!rReader.m_pDocShell)
6612 bRet=false;
6613 else
6614 rDestStorage = rReader.m_pDocShell->GetStorage();
6615 }
6616 return bRet;
6617}
6618
6619/**
6620 * When reading a single Box (which possibly is part of a group), we do
6621 * not yet have enough information to decide whether we need it as a TextField
6622 * or not.
6623 * So convert all of them as a precaution.
6624 * FIXME: Actually implement this!
6625 */
6626bool SwMSDffManager::ShapeHasText(sal_uLong, sal_uLong) const
6627{
6628 return true;
6629}
6630
6631bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl) const
6632{
6633 if (nLvl)
6634 --nLvl;
6635 // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6636 if ( sal::static_int_cast< sal_Int32>(nLvl) >= sal::static_int_cast< sal_Int32>(m_aApos.size()) )
6637 {
6638 return false;
6639 }
6640 auto aIter = std::find(m_aApos.begin() + nLvl, m_aApos.end(), true);
6641 return aIter != m_aApos.end();
6642}
6643
6644bool SwWW8ImplReader::InEqualApo(int nLvl) const
6645{
6646 // If we are in a table, see if an apo was inserted at the level below the table.
6647 if (nLvl)
6648 --nLvl;
6649 if (nLvl < 0 || o3tl::make_unsigned(nLvl) >= m_aApos.size())
6650 return false;
6651 return m_aApos[nLvl];
6652}
6653
6654namespace sw::hack
6655{
6656 Position::Position(const SwPosition &rPos)
6657 : maPtNode(rPos.nNode), mnPtContent(rPos.nContent.GetIndex())
6658 {
6659 }
6660
6661 Position::operator SwPosition() const
6662 {
6663 SwPosition aRet(maPtNode);
6664 aRet.nContent.Assign(maPtNode.GetNode().GetContentNode(), mnPtContent);
6665 return aRet;
6666 }
6667}
6668
6669SwMacroInfo::SwMacroInfo()
6670 : SdrObjUserData( SdrInventor::ScOrSwDraw, SW_UD_IMAPDATA2 )
6671 , mnShapeId(-1)
6672{
6673}
6674
6675SwMacroInfo::~SwMacroInfo()
6676{
6677}
6678
6679std::unique_ptr<SdrObjUserData> SwMacroInfo::Clone( SdrObject* /*pObj*/ ) const
6680{
6681 return std::unique_ptr<SdrObjUserData>(new SwMacroInfo( *this ));
6682}
6683
6684std::unique_ptr<SfxItemSet> SwWW8ImplReader::SetCurrentItemSet(std::unique_ptr<SfxItemSet> pItemSet)
6685{
6686 std::unique_ptr<SfxItemSet> xRet(std::move(m_xCurrentItemSet));
6687 m_xCurrentItemSet = std::move(pItemSet);
6688 return xRet;
6689}
6690
6691void SwWW8ImplReader::NotifyMacroEventRead()
6692{
6693 if (m_bNotifyMacroEventRead)
6694 return;
6695 uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
6696 comphelper::DocumentInfo::notifyMacroEventRead(xModel);
6697 m_bNotifyMacroEventRead = true;
6698}
6699
6700/* vim:set shiftwidth=4 softtabstop=4 expandtab: */