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' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
147 | using namespace ::com::sun::star; | |||
148 | using namespace sw::util; | |||
149 | using namespace sw::types; | |||
150 | using 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 | ||||
165 | static 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 | ||||
187 | static 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 | ||||
208 | namespace | |||
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 | ||||
219 | void 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 | ||||
359 | namespace { | |||
360 | ||||
361 | class BasicProjImportHelper | |||
362 | { | |||
363 | SwDocShell& mrDocShell; | |||
364 | uno::Reference< uno::XComponentContext > mxCtx; | |||
365 | public: | |||
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 | ||||
376 | bool 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 | ||||
396 | OUString 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 | ||||
415 | namespace { | |||
416 | ||||
417 | class Sttb : public TBBase | |||
418 | { | |||
419 | struct 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 | ||||
434 | public: | |||
435 | Sttb(); | |||
436 | ||||
437 | bool Read(SvStream &rS) override; | |||
438 | OUString getStringAtIndex( sal_uInt32 ); | |||
439 | }; | |||
440 | ||||
441 | } | |||
442 | ||||
443 | Sttb::Sttb() | |||
444 | : fExtend(0) | |||
445 | , cData(0) | |||
446 | , cbExtra(0) | |||
447 | { | |||
448 | } | |||
449 | ||||
450 | bool 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 | ||||
472 | OUString | |||
473 | Sttb::getStringAtIndex( sal_uInt32 index ) | |||
474 | { | |||
475 | OUString aRet; | |||
476 | if ( index < dataItems.size() ) | |||
477 | aRet = dataItems[ index ].data; | |||
478 | return aRet; | |||
479 | ||||
480 | } | |||
481 | ||||
482 | SwMSDffManager::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 | ||||
491 | sal_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> | |||
512 | SdrObject* 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 | ||||
561 | void 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 | ||||
571 | void SwMSDffManager::EnableFallbackStream() | |||
572 | { | |||
573 | pStData2 = pFallbackStream; | |||
574 | aEscherBlipCache = aOldEscherBlipCache; | |||
575 | aOldEscherBlipCache.clear(); | |||
576 | pFallbackStream = nullptr; | |||
577 | } | |||
578 | ||||
579 | sal_uInt16 SwWW8ImplReader::GetToggleAttrFlags() const | |||
580 | { | |||
581 | return m_xCtrlStck ? m_xCtrlStck->GetToggleAttrFlags() : 0; | |||
582 | } | |||
583 | ||||
584 | sal_uInt16 SwWW8ImplReader::GetToggleBiDiAttrFlags() const | |||
585 | { | |||
586 | return m_xCtrlStck ? m_xCtrlStck->GetToggleBiDiAttrFlags() : 0; | |||
587 | } | |||
588 | ||||
589 | void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags) | |||
590 | { | |||
591 | if (m_xCtrlStck) | |||
592 | m_xCtrlStck->SetToggleAttrFlags(nFlags); | |||
593 | } | |||
594 | ||||
595 | void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags) | |||
596 | { | |||
597 | if (m_xCtrlStck) | |||
598 | m_xCtrlStck->SetToggleBiDiAttrFlags(nFlags); | |||
599 | } | |||
600 | ||||
601 | SdrObject* 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 | */ | |||
1151 | void 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 | */ | |||
1173 | void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short ) | |||
1174 | { | |||
1175 | } | |||
1176 | ||||
1177 | /** | |||
1178 | * Stack | |||
1179 | */ | |||
1180 | void 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 | ||||
1194 | SwFltStackEntry* 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 | ||||
1219 | long 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 | ||||
1235 | static 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# | |||
1254 | void 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 | ||||
1292 | const 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 | ||||
1310 | sal_Int32 SwWW8FltControlStack::GetCurrAttrCP() const | |||
1311 | { | |||
1312 | return rReader.GetCurrAttrCP(); | |||
1313 | } | |||
1314 | ||||
1315 | bool 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 | */ | |||
1324 | void SwWW8FltControlStack::ClearParaEndPosition() | |||
1325 | { | |||
1326 | if ( !empty() ) | |||
1327 | return; | |||
1328 | ||||
1329 | rReader.ClearParaEndPosition(); | |||
1330 | } | |||
1331 | ||||
1332 | bool SwWW8FltControlStack::CheckSdOD(sal_Int32 nStart,sal_Int32 nEnd) | |||
1333 | { | |||
1334 | return rReader.IsParaEndInCPs(nStart,nEnd); | |||
1335 | } | |||
1336 | ||||
1337 | void 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 | ||||
1371 | void 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 | ||||
1481 | const 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 | ||||
1526 | const 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 | ||||
1557 | bool 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 | ||||
1580 | void 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 | */ | |||
1652 | void 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 | */ | |||
1812 | void 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 | ||||
1965 | void 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 | */ | |||
2009 | WW8ReaderSave::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 | ||||
2067 | void 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 | ||||
2109 | void 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 | */ | |||
2129 | long 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 | ||||
2204 | void 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 | ||||
2253 | void 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 | ||||
2266 | bool 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 | ||||
2272 | bool 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 | ||||
2301 | void 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 | ||||
2400 | bool wwSectionManager::SectionIsProtected(const wwSection &rSection) const | |||
2401 | { | |||
2402 | return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() ); | |||
2403 | } | |||
2404 | ||||
2405 | void 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 | ||||
2426 | void 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 | ||||
2498 | bool 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 | ||||
2524 | bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace) | |||
2525 | { | |||
2526 | return SetSpacing(rMyPam, nSpace, false); | |||
2527 | } | |||
2528 | ||||
2529 | bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace) | |||
2530 | { | |||
2531 | return SetSpacing(rMyPam, nSpace, true); | |||
2532 | } | |||
2533 | ||||
2534 | sal_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 | ||||
2541 | void 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 | ||||
2562 | bool 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 | ||||
2646 | bool 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 | ||||
2811 | rtl_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 | ||||
2829 | rtl_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 | ||||
2847 | rtl_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 | |||
2873 | rtl_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 | ||||
2896 | void 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 | */ | |||
2925 | static 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 | ||||
2977 | bool 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 | ||||
3008 | sal_Unicode SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar) | |||
3009 | { | |||
3010 | if (nChar >= 0x0030 && nChar <= 0x0039) | |||
3011 | return nChar + 0x0630; | |||
3012 | ||||
3013 | return nChar; | |||
3014 | } | |||
3015 | ||||
3016 | namespace | |||
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 | */ | |||
3033 | bool 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 | ||||
3219 | namespace | |||
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 | |||
3306 | void 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 | ||||
3434 | namespace sw { | |||
3435 | ||||
3436 | auto 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 | ||||
3456 | void 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 | */ | |||
3501 | bool 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 | ||||
3549 | bool 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 | ||||
3589 | bool 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 | ||||
3815 | void 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 | ||||
3856 | long 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 | |||
3978 | bool 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 | |||
3996 | void SwWW8ImplReader::ClearParaEndPosition() | |||
3997 | { | |||
3998 | if ( !m_aEndParaPos.empty() ) | |||
3999 | m_aEndParaPos.clear(); | |||
4000 | } | |||
4001 | ||||
4002 | void 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 | */ | |||
4036 | void 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 | ||||
4054 | bool 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 | ||||
4261 | SwWW8ImplReader::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 | ||||
4374 | SwWW8ImplReader::~SwWW8ImplReader() | |||
4375 | { | |||
4376 | } | |||
4377 | ||||
4378 | void 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 | ||||
4391 | void 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 | ||||
4441 | void 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 | */ | |||
4462 | static 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 | */ | |||
4493 | SwFormatPageDesc 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 | ||||
4532 | void 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 | ||||
4732 | void 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 | ||||
4745 | void 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 | ||||
4775 | void 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 | */ | |||
4812 | void 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 | ||||
4860 | static 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 | ||||
4891 | namespace { | |||
4892 | ||||
4893 | class WW8Customizations | |||
4894 | { | |||
4895 | SvStream* mpTableStream; | |||
4896 | WW8Fib mWw8Fib; | |||
4897 | public: | |||
4898 | WW8Customizations( SvStream*, WW8Fib const & ); | |||
4899 | void Import( SwDocShell* pShell ); | |||
4900 | }; | |||
4901 | ||||
4902 | } | |||
4903 | ||||
4904 | WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib ) | |||
4905 | { | |||
4906 | } | |||
4907 | ||||
4908 | void 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 | ||||
4936 | void 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 | ||||
4986 | ErrCode 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 | ||||
5489 | ErrCode 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 | ||||
5535 | namespace | |||
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 | |||
5700 | static 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 | ||||
5755 | ErrCode 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 | ||||
5949 | void 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 | ||||
6087 | const 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 | ||||
6123 | void 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 | ||||
6168 | ErrCode 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 | ||||
6250 | extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) Reader* ImportDOC() | |||
6251 | { | |||
6252 | return new WW8Reader; | |||
6253 | } | |||
6254 | ||||
6255 | namespace | |||
6256 | { | |||
6257 | class FontCacheGuard | |||
6258 | { | |||
6259 | public: | |||
6260 | ~FontCacheGuard() | |||
6261 | { | |||
6262 | FlushFontCache(); | |||
6263 | } | |||
6264 | }; | |||
6265 | } | |||
6266 | ||||
6267 | bool 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") | |||
6275 | { | |||
6276 | try | |||
6277 | { | |||
6278 | xStorage = tools::SvRef<SotStorage>(new SotStorage(rStream)); | |||
6279 | if (xStorage->GetError()) | |||
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 | } | |||
| ||||
6305 | ||||
6306 | extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool TestImportWW8(SvStream &rStream) | |||
6307 | { | |||
6308 | return TestImportDOC(rStream, "CWW8"); | |||
6309 | } | |||
6310 | ||||
6311 | extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool TestImportWW6(SvStream &rStream) | |||
6312 | { | |||
6313 | return TestImportDOC(rStream, "CWW6"); | |||
6314 | } | |||
6315 | ||||
6316 | extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool TestImportWW2(SvStream &rStream) | |||
6317 | { | |||
6318 | return TestImportDOC(rStream, "WW6"); | |||
| ||||
6319 | } | |||
6320 | ||||
6321 | ErrCode 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 | ||||
6342 | static 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 | ||||
6371 | ErrCode 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 | ||||
6431 | ErrCode 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 | ||||
6510 | SwReaderType WW8Reader::GetReaderType() | |||
6511 | { | |||
6512 | return SwReaderType::Storage | SwReaderType::Stream; | |||
6513 | } | |||
6514 | ||||
6515 | bool WW8Reader::HasGlossaries() const | |||
6516 | { | |||
6517 | return true; | |||
6518 | } | |||
6519 | ||||
6520 | bool 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 | ||||
6536 | bool 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 | */ | |||
6626 | bool SwMSDffManager::ShapeHasText(sal_uLong, sal_uLong) const | |||
6627 | { | |||
6628 | return true; | |||
6629 | } | |||
6630 | ||||
6631 | bool 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 | ||||
6644 | bool 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 | ||||
6654 | namespace 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 | ||||
6669 | SwMacroInfo::SwMacroInfo() | |||
6670 | : SdrObjUserData( SdrInventor::ScOrSwDraw, SW_UD_IMAPDATA2 ) | |||
6671 | , mnShapeId(-1) | |||
6672 | { | |||
6673 | } | |||
6674 | ||||
6675 | SwMacroInfo::~SwMacroInfo() | |||
6676 | { | |||
6677 | } | |||
6678 | ||||
6679 | std::unique_ptr<SdrObjUserData> SwMacroInfo::Clone( SdrObject* /*pObj*/ ) const | |||
6680 | { | |||
6681 | return std::unique_ptr<SdrObjUserData>(new SwMacroInfo( *this )); | |||
6682 | } | |||
6683 | ||||
6684 | std::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 | ||||
6691 | void 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: */ |