Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx
Warning:line 895, column 48
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name wrong.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <swtypes.hxx>
21
22#include <SwGrammarMarkUp.hxx>
23#include <ndtxt.hxx>
24#include <txtfrm.hxx>
25
26#include <osl/diagnose.h>
27
28SwWrongArea::SwWrongArea( const OUString& rType, WrongListType listType,
29 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag,
30 sal_Int32 nPos,
31 sal_Int32 nLen)
32: maType(rType), mnPos(nPos), mnLen(nLen), mpSubList(nullptr)
33{
34 mColor = getWrongAreaColor(listType, xPropertyBag);
35 mLineType = getWrongAreaLineType(listType, xPropertyBag);
36}
37
38SwWrongArea::SwWrongArea( const OUString& rType,
39 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag,
40 sal_Int32 nPos,
41 sal_Int32 nLen,
42 SwWrongList* pSubList)
43: maType(rType), mnPos(nPos), mnLen(nLen), mpSubList(pSubList), mLineType(WRONGAREA_NONE)
44{
45 if (pSubList != nullptr)
46 {
47 mColor = getWrongAreaColor(pSubList->GetWrongListType(), xPropertyBag);
48 mLineType = getWrongAreaLineType(pSubList->GetWrongListType(), xPropertyBag);
49 }
50}
51
52SwWrongList::SwWrongList( WrongListType eType ) :
53 meType (eType),
54 mnBeginInvalid(COMPLETE_STRING), // everything correct... (the invalid area starts beyond the string)
55 mnEndInvalid (COMPLETE_STRING)
56{
57 maList.reserve( 5 );
58}
59
60SwWrongList::~SwWrongList()
61{
62 ClearList();
63}
64
65SwWrongList* SwWrongList::Clone()
66{
67 SwWrongList* pClone = new SwWrongList( meType );
68 pClone->CopyFrom( *this );
69 return pClone;
70}
71
72void SwWrongList::CopyFrom( const SwWrongList& rCopy )
73{
74 maList = rCopy.maList;
75 meType = rCopy.meType;
76 mnBeginInvalid = rCopy.mnBeginInvalid;
77 mnEndInvalid = rCopy.mnEndInvalid;
78 for(SwWrongArea & i : maList)
79 {
80 if( i.mpSubList )
81 i.mpSubList = i.mpSubList->Clone();
82 }
83}
84
85void SwWrongList::ClearList()
86{
87 for (SwWrongArea & i : maList)
88 {
89 delete i.mpSubList;
90 i.mpSubList = nullptr;
91 }
92 maList.clear();
93}
94
95/** If a word is incorrectly selected, this method returns begin and length of it.
96
97 @param[in,out] rChk starting position of the word to check
98 @param[out] rLn length of the word
99
100 @return <true> if incorrectly selected, <false> otherwise
101 */
102bool SwWrongList::InWrongWord( sal_Int32 &rChk, sal_Int32 &rLn ) const
103{
104 const sal_uInt16 nPos = GetWrongPos( rChk );
105 if ( nPos >= Count() )
106 return false;
107 const sal_Int32 nWrPos = Pos( nPos );
108 if ( nWrPos <= rChk )
109 {
110 rLn = Len( nPos );
111 if( nWrPos + rLn <= rChk )
112 return false;
113 rChk = nWrPos;
114 return true;
115 }
116 return false;
117}
118
119/** Calculate first incorrectly selected area.
120
121 @param[in,out] rChk starting position of the word to check
122 @param[in,out] rLn length of the word
123
124 @return <true> if incorrectly selected area was found, <false> otherwise
125 */
126bool SwWrongList::Check( sal_Int32 &rChk, sal_Int32 &rLn ) const
127{
128 sal_uInt16 nPos = GetWrongPos( rChk );
129 rLn += rChk;
130
131 if( nPos == Count() )
132 return false;
133
134 sal_Int32 nWrPos = Pos( nPos );
135 sal_Int32 nEnd = nWrPos + Len( nPos );
136 if( nEnd == rChk )
137 {
138 ++nPos;
139 if( nPos == Count() )
140 return false;
141
142 nWrPos = Pos( nPos );
143 nEnd = nWrPos + Len( nPos );
144 }
145 if( nEnd > rChk && nWrPos < rLn )
146 {
147 if( nWrPos > rChk )
148 rChk = nWrPos;
149 if( nEnd < rLn )
150 rLn = nEnd;
151 rLn -= rChk;
152 return 0 != rLn;
153 }
154 return false;
155}
156
157/** Find next incorrectly selected position.
158
159 @param[in] rChk starting position of the word to check
160
161 @return starting position of incorrectly selected area, <COMPLETE_STRING> otherwise
162 */
163sal_Int32 SwWrongList::NextWrong( sal_Int32 nChk ) const
164{
165 sal_Int32 nRet = COMPLETE_STRING;
166 sal_uInt16 nPos = GetWrongPos( nChk );
167 if( nPos < Count() )
168 {
169 nRet = Pos( nPos );
170 if( nRet < nChk && nRet + Len( nPos ) <= nChk )
171 {
172 if( ++nPos < Count() )
173 nRet = Pos( nPos );
174 else
175 nRet = COMPLETE_STRING;
176 }
177 }
178 if( nRet > GetBeginInv() && nChk < GetEndInv() )
179 nRet = std::max(nChk, GetBeginInv());
180 return nRet;
181}
182
183/** Find the first position that is greater or equal to the given value.
184
185 @note Resulting position might be behind the last element of the array.
186 @param[in] nValue value for comparison
187
188 @return first position that is greater or equal to the given value
189 */
190sal_uInt16 SwWrongList::GetWrongPos( sal_Int32 nValue ) const
191{
192 sal_uInt16 nMax = Count();
193 sal_uInt16 nMin = 0;
194
195 if( nMax > 0 )
196 {
197 // For smart tag lists, we may not use a binary search. We return the
198 // position of the first smart tag which covers nValue
199 if ( !maList[0].maType.isEmpty() || maList[0].mpSubList )
200 {
201 auto aIter = std::find_if(maList.begin(), maList.end(),
202 [nValue](const SwWrongArea& rST) {
203 return (rST.mnPos <= nValue && nValue < rST.mnPos + rST.mnLen)
204 || (rST.mnPos > nValue);
205 });
206 return static_cast<sal_uInt16>(std::distance(maList.begin(), aIter));
207 }
208
209 --nMax;
210 sal_uInt16 nMid = 0;
211 while( nMin <= nMax )
212 {
213 nMid = nMin + ( nMax - nMin ) / 2;
214 const sal_Int32 nTmp = Pos( nMid );
215 if( nTmp == nValue )
216 {
217 nMin = nMid;
218 break;
219 }
220 else if( nTmp < nValue )
221 {
222 if( nTmp + Len( nMid ) >= nValue )
223 {
224 nMin = nMid;
225 break;
226 }
227 nMin = nMid + 1;
228 }
229 else if( nMid == 0 )
230 {
231 break;
232 }
233 else
234 nMax = nMid - 1;
235 }
236 }
237
238 // nMin now points to an index i into the wrong list which
239 // 1. nValue is inside [ Area[i].pos, Area[i].pos + Area[i].len ] (inclusive!!!)
240 // 2. nValue < Area[i].pos
241
242 return nMin;
243}
244
245void SwWrongList::Invalidate_( sal_Int32 nBegin, sal_Int32 nEnd )
246{
247 if ( nBegin < GetBeginInv() )
248 mnBeginInvalid = nBegin;
249 if ( nEnd > GetEndInv() || GetEndInv() == COMPLETE_STRING )
250 mnEndInvalid = nEnd;
251}
252
253void SwWrongList::SetInvalid( sal_Int32 nBegin, sal_Int32 nEnd )
254{
255 mnBeginInvalid = nBegin;
256 mnEndInvalid = nEnd;
257}
258
259/** Change all values after the given position.
260
261 Needed after insert/deletion of characters.
262
263 @param nPos position after that everything should be changed
264 @param nDiff amount how much the positions should be moved
265 */
266void SwWrongList::Move( sal_Int32 nPos, sal_Int32 nDiff )
267{
268 sal_uInt16 i = GetWrongPos( nPos );
269 if( nDiff < 0 )
270 {
271 const sal_Int32 nEnd = nPos - nDiff;
272 sal_uInt16 nLst = i;
273 bool bJump = false;
274 while( nLst < Count() && Pos( nLst ) < nEnd )
275 ++nLst;
276 if( nLst > i )
277 {
278 const sal_Int32 nWrPos = Pos( nLst - 1 );
279 if ( nWrPos <= nPos )
280 {
281 sal_Int32 nWrLen = Len( nLst - 1 );
282 // calculate new length of word
283 nWrLen = ( nEnd > nWrPos + nWrLen ) ?
284 nPos - nWrPos :
285 nWrLen + nDiff;
286 if( nWrLen )
287 {
288 maList[--nLst].mnLen = nWrLen;
289 bJump = true;
290 }
291 }
292 }
293 Remove( i, nLst - i );
294
295 if ( bJump )
296 ++i;
297 if( COMPLETE_STRING == GetBeginInv() )
298 SetInvalid( nPos ? nPos - 1 : nPos, nPos + 1 );
299 else
300 {
301 ShiftLeft( mnBeginInvalid, nPos, nEnd );
302 if( mnEndInvalid != COMPLETE_STRING )
303 ShiftLeft( mnEndInvalid, nPos, nEnd );
304 Invalidate_( nPos ? nPos - 1 : nPos, nPos + 1 );
305 }
306 }
307 else
308 {
309 const sal_Int32 nEnd = nPos + nDiff;
310 if( COMPLETE_STRING != GetBeginInv() )
311 {
312 if( mnBeginInvalid > nPos )
313 mnBeginInvalid += nDiff;
314 if( mnEndInvalid >= nPos && mnEndInvalid != COMPLETE_STRING )
315 mnEndInvalid += nDiff;
316 }
317 // If the pointer is in the middle of a wrong word,
318 // invalidation must happen from the beginning of that word.
319 if( i < Count() )
320 {
321 const sal_Int32 nWrPos = Pos( i );
322 if (nPos >= nWrPos)
323 {
324 Invalidate( nWrPos, nEnd );
325 const sal_Int32 nWrLen = Len( i ) + nDiff;
326 maList[i++].mnLen = nWrLen;
327 Invalidate( nWrPos, nWrPos + nWrLen );
328 }
329 }
330 else
331 Invalidate( nPos, nEnd );
332 }
333 while( i < Count() )
334 {
335 maList[i++].mnPos += nDiff;
336 }
337}
338
339// TODO: Complete documentation
340/** Remove given range of entries
341
342 For a given range [nPos, nPos + nLen[ and an index nIndex, this function
343 basically counts the number of SwWrongArea entries starting with nIndex
344 up to nPos + nLen. All these entries are removed.
345
346 @param rStart ???
347 @param rEnd ???
348 @param nPos starting position of the range
349 @param nLen length of the range
350 @param nIndex index to start lookup at
351 @param nCursorPos ???
352
353 @return <true> if ???
354 */
355auto SwWrongList::Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
356 sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos ) -> FreshState
357{
358 // length of word must be greater than 0
359 // only report a spelling error if the cursor position is outside the word,
360 // so that the user is not annoyed while typing
361 FreshState eRet = nLen
362 ? (nCursorPos > nPos + nLen || nCursorPos < nPos)
363 ? FreshState::FRESH
364 : FreshState::CURSOR
365 : FreshState::NOTHING;
366
367 sal_Int32 nWrPos = 0;
368 sal_Int32 nWrEnd = rEnd;
369 sal_uInt16 nCnt = nIndex;
370 if( nCnt < Count() )
371 {
372 nWrPos = Pos( nCnt );
373 if( nWrPos < nPos && rStart > nWrPos )
374 rStart = nWrPos;
375 }
376
377 while( nCnt < Count() )
378 {
379 nWrPos = Pos( nCnt );
380 if ( nWrPos >= nPos )
381 break;
382 nWrEnd = nWrPos + Len( nCnt++ );
383 }
384
385 if( nCnt < Count() && nWrPos == nPos && Len( nCnt ) == nLen )
386 {
387 ++nCnt;
388 eRet = FreshState::FRESH;
389 }
390 else
391 {
392 if (FreshState::FRESH == eRet)
393 {
394 if( rStart > nPos )
395 rStart = nPos;
396 nWrEnd = nPos + nLen;
397 }
398 }
399
400 nPos += nLen;
401
402 if( nCnt < Count() )
403 {
404 nWrPos = Pos( nCnt );
405 if( nWrPos < nPos && rStart > nWrPos )
406 rStart = nWrPos;
407 }
408
409 while( nCnt < Count() )
410 {
411 nWrPos = Pos( nCnt );
412 if ( nWrPos >= nPos )
413 break;
414 nWrEnd = nWrPos + Len( nCnt++ );
415 }
416
417 if( rEnd < nWrEnd )
418 rEnd = nWrEnd;
419
420 Remove( nIndex, nCnt - nIndex );
421
422 return eRet;
423}
424
425void SwWrongList::Invalidate( sal_Int32 nBegin, sal_Int32 nEnd )
426{
427 if (COMPLETE_STRING == GetBeginInv())
428 SetInvalid( nBegin, nEnd );
429 else
430 Invalidate_( nBegin, nEnd );
431}
432
433bool SwWrongList::InvalidateWrong( )
434{
435 if( Count() )
436 {
437 const sal_Int32 nFirst = Pos( 0 );
438 const sal_Int32 nLast = Pos( Count() - 1 ) + Len( Count() - 1 );
439 Invalidate( nFirst, nLast );
440 return true;
441 }
442 return false;
443}
444
445SwWrongList* SwWrongList::SplitList( sal_Int32 nSplitPos )
446{
447 SwWrongList *pRet = nullptr;
448 sal_uInt16 nLst = 0;
449 while( nLst < Count() && Pos( nLst ) < nSplitPos )
450 ++nLst;
451 if( nLst )
452 {
453 sal_Int32 nWrPos = Pos( nLst - 1 );
454 sal_Int32 nWrLen = Len( nLst - 1 );
455 if ( nWrPos+nWrLen > nSplitPos )
456 {
457 nWrLen += nWrPos - nSplitPos;
458 maList[--nLst].mnPos = nSplitPos;
459 maList[nLst].mnLen = nWrLen;
460 }
461 }
462 if( nLst )
463 {
464 if( WRONGLIST_GRAMMAR == GetWrongListType() )
465 pRet = new SwGrammarMarkUp();
466 else
467 pRet = new SwWrongList( GetWrongListType() );
468 pRet->Insert(0, maList.begin(), ( nLst >= maList.size() ? maList.end() : maList.begin() + nLst ) );
469 pRet->SetInvalid( GetBeginInv(), GetEndInv() );
470 pRet->Invalidate_( nSplitPos ? nSplitPos - 1 : nSplitPos, nSplitPos );
471 Remove( 0, nLst );
472 }
473 if( COMPLETE_STRING == GetBeginInv() )
474 SetInvalid( 0, 1 );
475 else
476 {
477 ShiftLeft( mnBeginInvalid, 0, nSplitPos );
478 if( mnEndInvalid != COMPLETE_STRING )
479 ShiftLeft( mnEndInvalid, 0, nSplitPos );
480 Invalidate_( 0, 1 );
481 }
482 for (nLst = 0; nLst < Count(); ++nLst )
483 {
484 maList[nLst].mnPos -= nSplitPos;
485 }
486 return pRet;
487}
488
489void SwWrongList::JoinList( SwWrongList* pNext, sal_Int32 nInsertPos )
490{
491 if (pNext)
492 {
493 OSL_ENSURE( GetWrongListType() == pNext->GetWrongListType(), "type mismatch with next list" )do { if (true && (!(GetWrongListType() == pNext->GetWrongListType
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx"
":" "493" ": "), "%s", "type mismatch with next list"); } } while
(false)
;
494
495 sal_uInt16 nCnt = Count();
496 pNext->Move( 0, nInsertPos );
497 Insert(nCnt, pNext->maList.begin(), pNext->maList.end());
498
499 Invalidate( pNext->GetBeginInv(), pNext->GetEndInv() );
500 if( nCnt && Count() > nCnt )
501 {
502 sal_Int32 nWrPos = Pos( nCnt );
503 sal_Int32 nWrLen = Len( nCnt );
504 if( !nWrPos )
505 {
506 nWrPos += nInsertPos;
507 nWrLen -= nInsertPos;
508 maList[nCnt].mnPos = nWrPos;
509 maList[nCnt].mnLen = nWrLen;
510 }
511 if( nWrPos == Pos( nCnt - 1 ) + Len( nCnt - 1 ) )
512 {
513 nWrLen += Len( nCnt - 1 );
514 maList[nCnt - 1].mnLen = nWrLen;
515 Remove( nCnt, 1 );
516 }
517 }
518 }
519 Invalidate( nInsertPos ? nInsertPos - 1 : nInsertPos, nInsertPos + 1 );
520}
521
522void SwWrongList::InsertSubList( sal_Int32 nNewPos, sal_Int32 nNewLen, sal_uInt16 nWhere, SwWrongList* pSubList )
523{
524 if (pSubList)
525 {
526 OSL_ENSURE( GetWrongListType() == pSubList->GetWrongListType(), "type mismatch with sub list" )do { if (true && (!(GetWrongListType() == pSubList->
GetWrongListType()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx"
":" "526" ": "), "%s", "type mismatch with sub list"); } } while
(false)
;
527 }
528 std::vector<SwWrongArea>::iterator i = maList.begin();
529 if ( nWhere >= maList.size() )
530 i = maList.end(); // robust
531 else
532 i += nWhere;
533 maList.insert(i, SwWrongArea( OUString(), nullptr, nNewPos, nNewLen, pSubList ) );
534}
535
536// New functions: Necessary because SwWrongList has been changed to use std::vector
537void SwWrongList::Insert(sal_uInt16 nWhere, std::vector<SwWrongArea>::iterator startPos, std::vector<SwWrongArea>::iterator const & endPos)
538{
539 std::vector<SwWrongArea>::iterator i = maList.begin();
540 if ( nWhere >= maList.size() )
541 i = maList.end(); // robust
542 else
543 i += nWhere;
544 maList.insert(i, startPos, endPos); // insert [startPos, endPos[ before i
545
546 // ownership of the sublist is passed to maList, therefore we have to set the
547 // pSubList-Pointers to 0
548 while ( startPos != endPos )
549 {
550 (*startPos).mpSubList = nullptr;
551 ++startPos;
552 }
553}
554
555void SwWrongList::Remove(sal_uInt16 nIdx, sal_uInt16 nLen )
556{
557 if ( nIdx >= maList.size() ) return;
558 std::vector<SwWrongArea>::iterator i1 = maList.begin();
559 i1 += nIdx;
560
561 std::vector<SwWrongArea>::iterator i2 = i1;
562 if ( nIdx + nLen >= static_cast<sal_uInt16>(maList.size()) )
563 i2 = maList.end(); // robust
564 else
565 i2 += nLen;
566
567 std::vector<SwWrongArea>::iterator iLoop = i1;
568 while ( iLoop != i2 )
569 {
570 delete (*iLoop).mpSubList;
571 ++iLoop;
572 }
573
574#if OSL_DEBUG_LEVEL1 > 0
575 const int nOldSize = Count();
576#endif
577
578 maList.erase(i1, i2);
579
580#if OSL_DEBUG_LEVEL1 > 0
581 OSL_ENSURE( Count() + nLen == nOldSize, "SwWrongList::Remove() trouble" )do { if (true && (!(Count() + nLen == nOldSize))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx"
":" "581" ": "), "%s", "SwWrongList::Remove() trouble"); } }
while (false)
;
582#endif
583}
584
585void SwWrongList::RemoveEntry( sal_Int32 nBegin, sal_Int32 nEnd ) {
586 std::vector<SwWrongArea>::const_iterator aEnd(maList.end());
587 auto aDelIter = std::find_if(maList.cbegin(), aEnd,
588 [nBegin](const SwWrongArea& rST) { return rST.mnPos >= nBegin; });
589 auto aIter = aDelIter;
590 if( WRONGLIST_GRAMMAR == GetWrongListType() )
591 {
592 if( nBegin < nEnd )
593 {
594 aIter = std::find_if(aDelIter, aEnd,
595 [nEnd](const SwWrongArea& rST) { return rST.mnPos >= nEnd; });
596 }
597 }
598 else
599 {
600 aIter = std::find_if(aDelIter, aEnd,
601 [nBegin, nEnd](const SwWrongArea& rST) {
602 return (rST.mnPos != nBegin) || ((rST.mnPos + rST.mnLen) != nEnd);
603 });
604 }
605 auto nDel = static_cast<sal_uInt16>(std::distance(aDelIter, aIter));
606 if( nDel )
607 {
608 auto nDelPos = static_cast<sal_uInt16>(std::distance(maList.cbegin(), aDelIter));
609 Remove( nDelPos, nDel );
610 }
611}
612
613bool SwWrongList::LookForEntry( sal_Int32 nBegin, sal_Int32 nEnd ) {
614 auto aIter = std::find_if(maList.begin(), maList.end(),
615 [nBegin](const SwWrongArea& rST) { return rST.mnPos >= nBegin; });
616 return aIter != maList.end()
617 && nBegin == (*aIter).mnPos
618 && nEnd == (*aIter).mnPos + (*aIter).mnLen;
619}
620
621void SwWrongList::Insert( const OUString& rType,
622 css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag,
623 sal_Int32 nNewPos, sal_Int32 nNewLen )
624{
625 auto aIter = std::find_if(maList.begin(), maList.end(),
626 [nNewPos](const SwWrongArea& rST) { return nNewPos <= rST.mnPos; });
627 if ( aIter != maList.end() && nNewPos == (*aIter).mnPos )
628 {
629 const sal_Int32 nSTPos = (*aIter).mnPos;
630
631 aIter = std::find_if(aIter, maList.end(),
632 [nSTPos, nNewLen](const SwWrongArea& rST) { return rST.mnPos != nSTPos || nNewLen < rST.mnLen; });
633 }
634
635 maList.insert(aIter, SwWrongArea( rType, meType, xPropertyBag, nNewPos, nNewLen) );
636}
637
638namespace sw {
639
640WrongListIteratorBase::WrongListIteratorBase(SwTextFrame const& rFrame,
641 SwWrongList const* (SwTextNode::*pGetWrongList)() const)
642 : m_pGetWrongList(pGetWrongList)
643 , m_pMergedPara(rFrame.GetMergedPara())
644 , m_CurrentExtent(0)
645 , m_CurrentIndex(0)
646 , m_pWrongList(m_pMergedPara
647 ? nullptr
648 : (rFrame.GetTextNodeFirst()->*pGetWrongList)())
649{
650}
651
652WrongListIteratorBase::WrongListIteratorBase(SwWrongList const& rWrongList)
653 : m_pGetWrongList(nullptr)
654 , m_pMergedPara(nullptr)
655 , m_CurrentExtent(0)
656 , m_CurrentIndex(0)
657 , m_pWrongList(&rWrongList)
658{
659}
660
661WrongListIterator::WrongListIterator(SwTextFrame const& rFrame,
662 SwWrongList const* (SwTextNode::*pGetWrongList)() const)
663 : WrongListIteratorBase(rFrame, pGetWrongList)
664{
665}
666
667WrongListIterator::WrongListIterator(SwWrongList const& rWrongList)
668 : WrongListIteratorBase(rWrongList)
669{
670}
671
672bool WrongListIterator::Check(TextFrameIndex & rStart, TextFrameIndex & rLen)
673{
674 if (m_pMergedPara)
675 {
676 if (rStart < m_CurrentIndex)
677 { // rewind
678 m_CurrentExtent = 0;
679 m_CurrentIndex = TextFrameIndex(0);
680 }
681 while (m_CurrentExtent < m_pMergedPara->extents.size())
682 {
683 sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
684 if (rStart + rLen <= m_CurrentIndex)
685 {
686 return false;
687 }
688 else if (rStart < m_CurrentIndex)
689 {
690 rLen -= m_CurrentIndex - rStart;
691 assert(0 < sal_Int32(rLen))(static_cast <bool> (0 < sal_Int32(rLen)) ? void (0)
: __assert_fail ("0 < sal_Int32(rLen)", "/home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx"
, 691, __extension__ __PRETTY_FUNCTION__))
;
692 rStart = m_CurrentIndex;
693 }
694 if (m_CurrentIndex <= rStart &&
695 rStart < m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart))
696 {
697 SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
698 // found the extent containing start - first, call Check
699 sal_Int32 nStart(rExtent.nStart + sal_Int32(rStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex));
700 sal_Int32 nLen;
701 if (sal_Int32(rLen) < rExtent.nEnd - nStart)
702 {
703 nLen = sal_Int32(rLen);
704 }
705 else
706 {
707 sal_Int32 nInLen(rLen);
708 nLen = rExtent.nEnd - nStart;
709 nInLen -= nLen;
710 for (size_t i = m_CurrentExtent + 1;
711 i < m_pMergedPara->extents.size(); ++i)
712 {
713 sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]);
714 if (rExtentEnd.pNode != rExtent.pNode)
715 {
716 break;
717 }
718 // add gap too
719 nLen += rExtentEnd.nStart - m_pMergedPara->extents[i-1].nEnd;
720 if (nInLen <= rExtentEnd.nEnd - rExtentEnd.nStart)
721 {
722 nLen += nInLen;
723 break;
724 }
725 nLen += rExtentEnd.nEnd - rExtentEnd.nStart;
726 nInLen -= rExtentEnd.nEnd - rExtentEnd.nStart;
727 }
728 }
729 if (pWrongList && pWrongList->Check(nStart, nLen))
730 {
731 // check if there's overlap with this extent
732 if (rExtent.nStart <= nStart && nStart < rExtent.nEnd)
733 {
734 // yes - now compute end position / length
735 sal_Int32 const nEnd(nStart + nLen);
736 rStart = m_CurrentIndex + TextFrameIndex(nStart - rExtent.nStart);
737 TextFrameIndex const nOrigLen(rLen);
738 if (nEnd <= rExtent.nEnd)
739 {
740 rLen = TextFrameIndex(nEnd - nStart);
741 }
742 else // have to search other extents for the end...
743 {
744 rLen = TextFrameIndex(rExtent.nEnd - nStart);
745 for (size_t i = m_CurrentExtent + 1;
746 i < m_pMergedPara->extents.size(); ++i)
747 {
748 sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]);
749 if (rExtentEnd.pNode != rExtent.pNode
750 || nEnd <= rExtentEnd.nStart)
751 {
752 break;
753 }
754 if (nEnd <= rExtentEnd.nEnd)
755 {
756 rLen += TextFrameIndex(nEnd - rExtentEnd.nStart);
757 break;
758 }
759 rLen += TextFrameIndex(rExtentEnd.nEnd - rExtentEnd.nStart);
760 }
761 }
762 assert(rLen <= nOrigLen)(static_cast <bool> (rLen <= nOrigLen) ? void (0) : __assert_fail
("rLen <= nOrigLen", "/home/maarten/src/libreoffice/core/sw/source/core/text/wrong.cxx"
, 762, __extension__ __PRETTY_FUNCTION__))
; (void) nOrigLen;
763 return true;
764 }
765 }
766 }
767 m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
768 ++m_CurrentExtent;
769 }
770 return false;
771 }
772 else if (m_pWrongList)
773 {
774 sal_Int32 nStart(rStart);
775 sal_Int32 nLen(rLen);
776 bool const bRet(m_pWrongList->Check(nStart, nLen));
777 rStart = TextFrameIndex(nStart);
778 rLen = TextFrameIndex(nLen);
779 return bRet;
780 }
781 return false;
782}
783
784const SwWrongArea*
785WrongListIterator::GetWrongElement(TextFrameIndex const nStart)
786{
787 if (m_pMergedPara)
788 {
789 if (nStart < m_CurrentIndex)
790 { // rewind
791 m_CurrentExtent = 0;
792 m_CurrentIndex = TextFrameIndex(0);
793 }
794 while (m_CurrentExtent < m_pMergedPara->extents.size())
795 {
796 sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
797 if (m_CurrentIndex <= nStart &&
798 nStart <= m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart))
799 {
800 // note: the returned object isn't wrapped because fntcache.cxx
801 // does not look at its positions, only its formatting props
802 SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
803 if (pWrongList)
804 {
805 sal_Int32 const nNStart(rExtent.nStart + sal_Int32(nStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex));
806 sal_Int16 const nPos(pWrongList->GetWrongPos(nNStart));
807 return pWrongList->GetElement(nPos);
808 }
809 }
810 m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
811 ++m_CurrentExtent;
812 }
813 return nullptr;
814 }
815 else if (m_pWrongList)
816 {
817 sal_Int16 const nPos(m_pWrongList->GetWrongPos(sal_Int32(nStart)));
818 return m_pWrongList->GetElement(nPos);
819 }
820 return nullptr;
821}
822
823WrongListIteratorCounter::WrongListIteratorCounter(SwTextFrame const& rFrame,
824 SwWrongList const* (SwTextNode::*pGetWrongList)() const)
825 : WrongListIteratorBase(rFrame, pGetWrongList)
826{
827}
828
829WrongListIteratorCounter::WrongListIteratorCounter(SwWrongList const& rWrongList)
830 : WrongListIteratorBase(rWrongList)
831{
832}
833
834sal_uInt16 WrongListIteratorCounter::GetElementCount()
835{
836 if (m_pMergedPara)
837 {
838 sal_uInt16 nRet(0);
839 m_CurrentExtent = 0;
840 m_CurrentIndex = TextFrameIndex(0);
841 SwNode const* pNode(nullptr);
842 sal_uInt16 InCurrentNode(0);
843 while (m_CurrentExtent < m_pMergedPara->extents.size())
844 {
845 sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
846 if (rExtent.pNode != pNode)
847 {
848 InCurrentNode = 0;
849 pNode = rExtent.pNode;
850 }
851 SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
852 for (; pWrongList && InCurrentNode < pWrongList->Count(); ++InCurrentNode)
853 {
854 SwWrongArea const*const pWrong(pWrongList->GetElement(InCurrentNode));
855 TextFrameIndex const nExtentEnd(
856 m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart));
857 if (nExtentEnd <= TextFrameIndex(pWrong->mnPos))
858 {
859 break; // continue outer loop
860 }
861 if (m_CurrentIndex < TextFrameIndex(pWrong->mnPos + pWrong->mnLen))
862 {
863 ++nRet;
864 }
865 }
866 m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
867 ++m_CurrentExtent;
868 }
869 return nRet;
870 }
871 else if (m_pWrongList)
872 {
873 return m_pWrongList->Count();
874 }
875 return 0;
876}
877
878std::optional<std::pair<TextFrameIndex, TextFrameIndex>>
879WrongListIteratorCounter::GetElementAt(sal_uInt16 nIndex)
880{
881 if (m_pMergedPara)
1
Assuming field 'm_pMergedPara' is non-null
2
Taking true branch
882 {
883 m_CurrentExtent = 0;
884 m_CurrentIndex = TextFrameIndex(0);
885 SwNode const* pNode(nullptr);
886 sal_uInt16 InCurrentNode(0);
887 while (m_CurrentExtent < m_pMergedPara->extents.size())
3
Assuming the condition is true
4
Loop condition is true. Entering loop body
888 {
889 sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
890 if (rExtent.pNode != pNode)
5
Assuming 'pNode' is equal to field 'pNode'
6
Taking false branch
891 {
892 InCurrentNode = 0;
893 pNode = rExtent.pNode;
894 }
895 SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
7
Called C++ object pointer is null
896 for (; pWrongList && InCurrentNode < pWrongList->Count(); ++InCurrentNode)
897 {
898 SwWrongArea const*const pWrong(pWrongList->GetElement(InCurrentNode));
899 TextFrameIndex const nExtentEnd(
900 m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart));
901 if (nExtentEnd <= TextFrameIndex(pWrong->mnPos))
902 {
903 break; // continue outer loop
904 }
905 if (m_CurrentIndex < TextFrameIndex(pWrong->mnPos + pWrong->mnLen))
906 {
907 if (nIndex == 0)
908 {
909 return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>(
910 std::pair<TextFrameIndex, TextFrameIndex>(
911 m_CurrentIndex - TextFrameIndex(rExtent.nStart -
912 std::max(rExtent.nStart, pWrong->mnPos)),
913 m_CurrentIndex - TextFrameIndex(rExtent.nStart -
914 std::min(pWrong->mnPos + pWrong->mnLen, rExtent.nEnd))));
915 }
916 --nIndex;
917 }
918 }
919 m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
920 ++m_CurrentExtent;
921 }
922 return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>();
923 }
924 else if (m_pWrongList)
925 {
926 SwWrongArea const*const pWrong(m_pWrongList->GetElement(nIndex));
927 return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>(
928 std::pair<TextFrameIndex, TextFrameIndex>(
929 TextFrameIndex(pWrong->mnPos),
930 TextFrameIndex(pWrong->mnPos + pWrong->mnLen)));
931 }
932 return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>();
933}
934
935} // namespace sw
936
937/* vim:set shiftwidth=4 softtabstop=4 expandtab: */