Bug Summary

File:home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx
Warning:line 593, column 12
Use of memory after it is freed

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 parrtf.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 -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 SVT_DLLIMPLEMENTATION -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/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/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/svtools/source/inc -I /home/maarten/src/libreoffice/core/svtools/inc -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/svtools/source/svrtf/parrtf.cxx

/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.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 <sal/config.h>
21#include <sal/log.hxx>
22
23#include <rtl/character.hxx>
24#include <rtl/strbuf.hxx>
25#include <rtl/tencinfo.h>
26#include <rtl/ustrbuf.hxx>
27#include <tools/stream.hxx>
28#include <tools/debug.hxx>
29#include <svtools/rtftoken.h>
30#include <svtools/parrtf.hxx>
31
32const int MAX_STRING_LEN = 1024;
33const int MAX_TOKEN_LEN = 128;
34
35#define RTF_ISDIGIT( c )rtl::isAsciiDigit(c) rtl::isAsciiDigit(c)
36#define RTF_ISALPHA( c )rtl::isAsciiAlpha(c) rtl::isAsciiAlpha(c)
37
38SvRTFParser::SvRTFParser( SvStream& rIn, sal_uInt8 nStackSize )
39 : SvParser<int>( rIn, nStackSize )
40 , nOpenBrakets(0)
41 , eCodeSet(RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1)))
42 , nUCharOverread(1)
43{
44 // default is ANSI-CodeSet
45 SetSrcEncoding( RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1)) );
46 bRTF_InTextRead = false;
47}
48
49SvRTFParser::~SvRTFParser()
50{
51}
52
53
54int SvRTFParser::GetNextToken_()
55{
56 int nRet = 0;
57 do {
58 bool bNextCh = true;
59 switch( nNextCh )
60 {
61 case '\\':
62 {
63 // control characters
64 nNextCh = GetNextChar();
65 switch( nNextCh )
66 {
67 case '{':
68 case '}':
69 case '\\':
70 case '+': // I found it in a RTF-file
71 case '~': // nonbreaking space
72 case '-': // optional hyphen
73 case '_': // nonbreaking hyphen
74 case '\'': // HexValue
75 nNextCh = '\\';
76 rInput.SeekRel( -1 );
77 ScanText();
78 nRet = RTF_TEXTTOKEN;
79 bNextCh = 0 == nNextCh;
80 break;
81
82 case '*': // ignoreflag
83 nRet = RTF_IGNOREFLAG;
84 break;
85 case ':': // subentry in an index entry
86 nRet = RTF_SUBENTRYINDEX;
87 break;
88 case '|': // formula-character
89 nRet = RTF_FORMULA;
90 break;
91
92 case 0x0a:
93 case 0x0d:
94 nRet = RTF_PAR;
95 break;
96
97 default:
98 if( RTF_ISALPHA( nNextCh )rtl::isAsciiAlpha(nNextCh) )
99 {
100 aToken = "\\";
101 {
102 OUStringBuffer aStrBuffer( MAX_TOKEN_LEN );
103 do {
104 aStrBuffer.appendUtf32(nNextCh);
105 nNextCh = GetNextChar();
106 } while( RTF_ISALPHA( nNextCh )rtl::isAsciiAlpha(nNextCh) );
107 aToken += aStrBuffer;
108 }
109
110 // minus before numeric parameters
111 bool bNegValue = false;
112 if( '-' == nNextCh )
113 {
114 bNegValue = true;
115 nNextCh = GetNextChar();
116 }
117
118 // possible numeric parameter
119 if( RTF_ISDIGIT( nNextCh )rtl::isAsciiDigit(nNextCh) )
120 {
121 OUStringBuffer aNumber;
122 do {
123 aNumber.append(static_cast<sal_Unicode>(nNextCh));
124 nNextCh = GetNextChar();
125 } while( RTF_ISDIGIT( nNextCh )rtl::isAsciiDigit(nNextCh) );
126 nTokenValue = aNumber.toString().toInt32();
127 if( bNegValue )
128 nTokenValue = -nTokenValue;
129 bTokenHasValue=true;
130 }
131 else if( bNegValue ) // restore minus
132 {
133 nNextCh = '-';
134 rInput.SeekRel( -1 );
135 }
136 if( ' ' == nNextCh ) // blank is part of token!
137 nNextCh = GetNextChar();
138
139 // search for the token in the table:
140 if( 0 == (nRet = GetRTFToken( aToken )) )
141 // Unknown Control
142 nRet = RTF_UNKNOWNCONTROL;
143
144 // bug 76812 - unicode token handled as normal text
145 bNextCh = false;
146 switch( nRet )
147 {
148 case RTF_UC:
149 if( 0 <= nTokenValue )
150 {
151 nUCharOverread = static_cast<sal_uInt8>(nTokenValue);
152 if (!aParserStates.empty())
153 {
154 //cmc: other ifdef breaks #i3584
155 aParserStates.top().nUCharOverread = nUCharOverread;
156 }
157 }
158 aToken.clear(); // #i47831# erase token to prevent the token from being treated as text
159 // read next token
160 nRet = 0;
161 break;
162
163 case RTF_UPR:
164 if (!_inSkipGroup) {
165 // UPR - overread the group with the ansi
166 // information
167 int nNextToken;
168 do
169 {
170 nNextToken = GetNextToken_();
171 }
172 while (nNextToken != '{' && nNextToken != sal_Unicode(EOF(-1)));
173
174 SkipGroup();
175 GetNextToken_(); // overread the last bracket
176 nRet = 0;
177 }
178 break;
179
180 case RTF_U:
181 if( !bRTF_InTextRead )
182 {
183 nRet = RTF_TEXTTOKEN;
184 aToken = OUString( static_cast<sal_Unicode>(nTokenValue) );
185
186 // overread the next n "RTF" characters. This
187 // can be also \{, \}, \'88
188 for( sal_uInt8 m = 0; m < nUCharOverread; ++m )
189 {
190 sal_uInt32 cAnsi = nNextCh;
191 while( 0xD == cAnsi )
192 cAnsi = GetNextChar();
193 while( 0xA == cAnsi )
194 cAnsi = GetNextChar();
195
196 if( '\\' == cAnsi &&
197 '\'' == GetNextChar() )
198 // skip HexValue
199 GetHexValue();
200 nNextCh = GetNextChar();
201 }
202 ScanText();
203 bNextCh = 0 == nNextCh;
204 }
205 break;
206 }
207 }
208 else if( SvParserState::Pending != eState )
209 {
210 // Bug 34631 - "\ " read on - Blank as character
211 // eState = SvParserState::Error;
212 bNextCh = false;
213 }
214 break;
215 }
216 }
217 break;
218
219 case sal_Unicode(EOF(-1)):
220 eState = SvParserState::Accepted;
221 nRet = nNextCh;
222 break;
223
224 case '{':
225 {
226 if( 0 <= nOpenBrakets )
227 {
228 RtfParserState_Impl aState( nUCharOverread, GetSrcEncoding() );
229 aParserStates.push( aState );
230 }
231 ++nOpenBrakets;
232 DBG_ASSERT(do { if (true && (!(static_cast<size_t>(nOpenBrakets
) == aParserStates.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "234" ": "), "%s", "ParserStateStack unequal to bracket count"
); } } while (false)
233 static_cast<size_t>(nOpenBrakets) == aParserStates.size(),do { if (true && (!(static_cast<size_t>(nOpenBrakets
) == aParserStates.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "234" ": "), "%s", "ParserStateStack unequal to bracket count"
); } } while (false)
234 "ParserStateStack unequal to bracket count" )do { if (true && (!(static_cast<size_t>(nOpenBrakets
) == aParserStates.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "234" ": "), "%s", "ParserStateStack unequal to bracket count"
); } } while (false)
;
235 nRet = nNextCh;
236 }
237 break;
238
239 case '}':
240 --nOpenBrakets;
241 if( 0 <= nOpenBrakets )
242 {
243 aParserStates.pop();
244 if( !aParserStates.empty() )
245 {
246 const RtfParserState_Impl& rRPS =
247 aParserStates.top();
248 nUCharOverread = rRPS.nUCharOverread;
249 SetSrcEncoding( rRPS.eCodeSet );
250 }
251 else
252 {
253 nUCharOverread = 1;
254 SetSrcEncoding( GetCodeSet() );
255 }
256 }
257 DBG_ASSERT(do { if (true && (!(static_cast<size_t>(nOpenBrakets
) == aParserStates.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "259" ": "), "%s", "ParserStateStack unequal to bracket count"
); } } while (false)
258 static_cast<size_t>(nOpenBrakets) == aParserStates.size(),do { if (true && (!(static_cast<size_t>(nOpenBrakets
) == aParserStates.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "259" ": "), "%s", "ParserStateStack unequal to bracket count"
); } } while (false)
259 "ParserStateStack unequal to bracket count" )do { if (true && (!(static_cast<size_t>(nOpenBrakets
) == aParserStates.size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "259" ": "), "%s", "ParserStateStack unequal to bracket count"
); } } while (false)
;
260 nRet = nNextCh;
261 break;
262
263 case 0x0d:
264 case 0x0a:
265 break;
266
267 default:
268 // now normal text follows
269 ScanText();
270 nRet = RTF_TEXTTOKEN;
271 bNextCh = 0 == nNextCh;
272 break;
273 }
274
275 if( bNextCh )
276 nNextCh = GetNextChar();
277
278 } while( !nRet && SvParserState::Working == eState );
279 return nRet;
280}
281
282
283sal_Unicode SvRTFParser::GetHexValue()
284{
285 // collect Hex values
286 int n;
287 sal_Unicode nHexVal = 0;
288
289 for( n = 0; n < 2; ++n )
290 {
291 nHexVal *= 16;
292 nNextCh = GetNextChar();
293 if( nNextCh >= '0' && nNextCh <= '9' )
294 nHexVal += (nNextCh - 48);
295 else if( nNextCh >= 'a' && nNextCh <= 'f' )
296 nHexVal += (nNextCh - 87);
297 else if( nNextCh >= 'A' && nNextCh <= 'F' )
298 nHexVal += (nNextCh - 55);
299 }
300 return nHexVal;
301}
302
303void SvRTFParser::ScanText()
304{
305 const sal_Unicode cBreak = 0;
306 OUStringBuffer aStrBuffer;
307 bool bContinue = true;
308 while( bContinue && IsParserWorking() && aStrBuffer.getLength() < MAX_STRING_LEN)
309 {
310 bool bNextCh = true;
311 switch( nNextCh )
312 {
313 case '\\':
314 {
315 nNextCh = GetNextChar();
316 switch (nNextCh)
317 {
318 case '\'':
319 {
320
321 OStringBuffer aByteString;
322 while (true)
323 {
324 char c = static_cast<char>(GetHexValue());
325 /*
326 * Note: \'00 is a valid internal character in a
327 * string in RTF. OStringBuffer supports
328 * appending nulls fine
329 */
330 aByteString.append(c);
331
332 bool bBreak = false;
333 bool bEOF = false;
334 char nSlash = '\\';
335 while (!bBreak)
336 {
337 auto next = GetNextChar();
338 if (sal_Unicode(EOF(-1)) == next)
339 {
340 bEOF = true;
341 break;
342 }
343 if (next>0xFF) // fix for #i43933# and #i35653#
344 {
345 if (!aByteString.isEmpty())
346 aStrBuffer.append( OStringToOUString(aByteString.makeStringAndClear(), GetSrcEncoding()) );
347 aStrBuffer.append(static_cast<sal_Unicode>(next));
348
349 continue;
350 }
351 nSlash = static_cast<char>(next);
352 while (nSlash == 0xD || nSlash == 0xA)
353 nSlash = static_cast<char>(GetNextChar());
354
355 switch (nSlash)
356 {
357 case '{':
358 case '}':
359 case '\\':
360 bBreak = true;
361 break;
362 default:
363 aByteString.append(nSlash);
364 break;
365 }
366 }
367
368 if (bEOF)
369 {
370 bContinue = false; // abort, string together
371 break;
372 }
373
374 nNextCh = GetNextChar();
375
376 if (nSlash != '\\' || nNextCh != '\'')
377 {
378 rInput.SeekRel(-1);
379 nNextCh = static_cast<unsigned char>(nSlash);
380 break;
381 }
382 }
383
384 bNextCh = false;
385
386 if (!aByteString.isEmpty())
387 aStrBuffer.append( OStringToOUString(aByteString.makeStringAndClear(), GetSrcEncoding()) );
388 }
389 break;
390 case '\\':
391 case '}':
392 case '{':
393 case '+': // I found in a RTF file
394 aStrBuffer.append(sal_Unicode(nNextCh));
395 break;
396 case '~': // nonbreaking space
397 aStrBuffer.append(u'\x00A0');
398 break;
399 case '-': // optional hyphen
400 aStrBuffer.append(u'\x00AD');
401 break;
402 case '_': // nonbreaking hyphen
403 aStrBuffer.append(u'\x2011');
404 break;
405
406 case 'u':
407 // read UNI-Code characters
408 {
409 nNextCh = GetNextChar();
410 rInput.SeekRel( -2 );
411
412 if( '-' == nNextCh || RTF_ISDIGIT( nNextCh )rtl::isAsciiDigit(nNextCh) )
413 {
414 bRTF_InTextRead = true;
415
416 OUString sSave( aToken );
417 nNextCh = '\\';
418 int nToken = GetNextToken_();
419 DBG_ASSERT( RTF_U == nToken, "still not a UNI-Code character" )do { if (true && (!(RTF_U == nToken))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "419" ": "), "%s", "still not a UNI-Code character"); } }
while (false)
;
420 // don't convert symbol chars
421 aStrBuffer.append(static_cast< sal_Unicode >(nTokenValue));
422
423 // overread the next n "RTF" characters. This
424 // can be also \{, \}, \'88
425 for( sal_uInt8 m = 0; m < nUCharOverread; ++m )
426 {
427 sal_Unicode cAnsi = nNextCh;
428 while( 0xD == cAnsi )
429 cAnsi = GetNextChar();
430 while( 0xA == cAnsi )
431 cAnsi = GetNextChar();
432
433 if( '\\' == cAnsi &&
434 '\'' == GetNextChar() )
435 // skip HexValue
436 GetHexValue();
437 nNextCh = GetNextChar();
438 }
439 bNextCh = false;
440 aToken = sSave;
441 bRTF_InTextRead = false;
442 }
443 else if ( 'c' == nNextCh )
444 {
445 // Prevent text breaking into multiple tokens.
446 rInput.SeekRel( 2 );
447 nNextCh = GetNextChar();
448 if (RTF_ISDIGIT( nNextCh )rtl::isAsciiDigit(nNextCh))
449 {
450 sal_uInt8 nNewOverread = 0 ;
451 do {
452 nNewOverread *= 10;
453 nNewOverread += nNextCh - '0';
454 nNextCh = GetNextChar();
455 } while ( RTF_ISDIGIT( nNextCh )rtl::isAsciiDigit(nNextCh) );
456 nUCharOverread = nNewOverread;
457 if (!aParserStates.empty())
458 aParserStates.top().nUCharOverread = nNewOverread;
459 }
460 bNextCh = 0x20 == nNextCh;
461 }
462 else
463 {
464 nNextCh = '\\';
465 bContinue = false; // abort, string together
466 }
467 }
468 break;
469
470 default:
471 rInput.SeekRel( -1 );
472 nNextCh = '\\';
473 bContinue = false; // abort, string together
474 break;
475 }
476 }
477 break;
478
479 case sal_Unicode(EOF(-1)):
480 eState = SvParserState::Error;
481 [[fallthrough]];
482 case '{':
483 case '}':
484 bContinue = false;
485 break;
486
487 case 0x0a:
488 case 0x0d:
489 break;
490
491 default:
492 if( nNextCh == cBreak || aStrBuffer.getLength() >= MAX_STRING_LEN)
493 bContinue = false;
494 else
495 {
496 do {
497 // all other characters end up in the text
498 aStrBuffer.appendUtf32(nNextCh);
499
500 if (sal_Unicode(EOF(-1)) == (nNextCh = GetNextChar()))
501 {
502 if (!aStrBuffer.isEmpty())
503 aToken += aStrBuffer;
504 return;
505 }
506 } while
507 (
508 (RTF_ISALPHA(nNextCh)rtl::isAsciiAlpha(nNextCh) || RTF_ISDIGIT(nNextCh)rtl::isAsciiDigit(nNextCh)) &&
509 (aStrBuffer.getLength() < MAX_STRING_LEN)
510 );
511 bNextCh = false;
512 }
513 }
514
515 if( bContinue && bNextCh )
516 nNextCh = GetNextChar();
517 }
518
519 if (!aStrBuffer.isEmpty())
520 aToken += aStrBuffer;
521}
522
523
524short SvRTFParser::_inSkipGroup=0;
525
526void SvRTFParser::SkipGroup()
527{
528 short nBrackets=1;
529 if (_inSkipGroup>0)
530 return;
531 _inSkipGroup++;
532//#i16185# faking \bin keyword
533 do
534 {
535 switch (nNextCh)
536 {
537 case '{':
538 ++nBrackets;
539 break;
540 case '}':
541 if (!--nBrackets) {
542 _inSkipGroup--;
543 return;
544 }
545 break;
546 }
547 int nToken = GetNextToken_();
548 if (nToken == RTF_BIN)
549 {
550 rInput.SeekRel(-1);
551 SAL_WARN_IF(nTokenValue < 0, "svtools", "negative value argument for rtf \\bin keyword")do { if (true && (nTokenValue < 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "svtools")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "negative value argument for rtf \\bin keyword"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools"
), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "551" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "negative value argument for rtf \\bin keyword"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "negative value argument for rtf \\bin keyword"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools"),
("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "551" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "negative value argument for rtf \\bin keyword") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools"
), ("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "551" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "negative value argument for rtf \\bin keyword"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "negative value argument for rtf \\bin keyword"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("svtools"),
("/home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx"
":" "551" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
552 if (nTokenValue > 0)
553 rInput.SeekRel(nTokenValue);
554 nNextCh = GetNextChar();
555 }
556 while (nNextCh==0xa || nNextCh==0xd)
557 {
558 nNextCh = GetNextChar();
559 }
560 } while (sal_Unicode(EOF(-1)) != nNextCh && IsParserWorking());
561
562 if( SvParserState::Pending != eState && '}' != nNextCh )
563 eState = SvParserState::Error;
564 _inSkipGroup--;
565}
566
567void SvRTFParser::ReadUnknownData() { SkipGroup(); }
568void SvRTFParser::ReadBitmapData() { SkipGroup(); }
569
570
571SvParserState SvRTFParser::CallParser()
572{
573 char cFirstCh;
574 nNextChPos = rInput.Tell();
575 rInput.ReadChar( cFirstCh );
576 nNextCh = static_cast<unsigned char>(cFirstCh);
577 eState = SvParserState::Working;
578 nOpenBrakets = 0;
579 eCodeSet = RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1));
580 SetSrcEncoding( eCodeSet );
581
582 // the first two tokens should be '{' and \\rtf !!
583 if( '{' == GetNextToken() && RTF_RTF == GetNextToken() )
1
Assuming the condition is true
2
Assuming the condition is true
3
Taking true branch
584 {
585 AddFirstRef();
586 Continue( 0 );
587 if( SvParserState::Pending != eState )
4
Assuming Pending is not equal to field 'eState'
5
Taking true branch
588 ReleaseRef(); // now parser is not needed anymore
6
Calling 'SvRefBase::ReleaseRef'
13
Returning; memory was released
589 }
590 else
591 eState = SvParserState::Error;
592
593 return eState;
14
Use of memory after it is freed
594}
595
596void SvRTFParser::Continue( int nToken )
597{
598// DBG_ASSERT( SVPAR_CS_DONTKNOW == GetCharSet(),
599// "Characterset was changed." );
600
601 if( !nToken )
602 nToken = GetNextToken();
603
604 bool bLooping = false;
605
606 while (IsParserWorking() && !bLooping)
607 {
608 auto nCurrentTokenIndex = m_nTokenIndex;
609 auto nCurrentToken = nToken;
610
611 SaveState( nToken );
612 switch( nToken )
613 {
614 case '}':
615 if( nOpenBrakets )
616 goto NEXTTOKEN;
617 eState = SvParserState::Accepted;
618 break;
619
620 case '{':
621 // an unknown group ?
622 {
623 if( RTF_IGNOREFLAG != GetNextToken() )
624 nToken = SkipToken();
625 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
626 nToken = SkipToken( -2 );
627 else
628 {
629 // filter immediately
630 ReadUnknownData();
631 nToken = GetNextToken();
632 if( '}' != nToken )
633 eState = SvParserState::Error;
634 break; // move to next token!!
635 }
636 }
637 goto NEXTTOKEN;
638
639 case RTF_UNKNOWNCONTROL:
640 break; // skip unknown token
641 case RTF_NEXTTYPE:
642 case RTF_ANSITYPE:
643 eCodeSet = RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1));
644 SetSrcEncoding( eCodeSet );
645 break;
646 case RTF_MACTYPE:
647 eCodeSet = RTL_TEXTENCODING_APPLE_ROMAN(((rtl_TextEncoding) 2));
648 SetSrcEncoding( eCodeSet );
649 break;
650 case RTF_PCTYPE:
651 eCodeSet = RTL_TEXTENCODING_IBM_437(((rtl_TextEncoding) 3));
652 SetSrcEncoding( eCodeSet );
653 break;
654 case RTF_PCATYPE:
655 eCodeSet = RTL_TEXTENCODING_IBM_850(((rtl_TextEncoding) 4));
656 SetSrcEncoding( eCodeSet );
657 break;
658 case RTF_ANSICPG:
659 eCodeSet = rtl_getTextEncodingFromWindowsCodePage(nTokenValue);
660 SetSrcEncoding(eCodeSet);
661 break;
662 default:
663NEXTTOKEN:
664 NextToken( nToken );
665 break;
666 }
667 if( IsParserWorking() )
668 SaveState( 0 ); // processed till here,
669 // continue with new token!
670 nToken = GetNextToken();
671 bLooping = nCurrentTokenIndex == m_nTokenIndex && nToken == nCurrentToken;
672 }
673 if( SvParserState::Accepted == eState && 0 < nOpenBrakets )
674 eState = SvParserState::Error;
675}
676
677void SvRTFParser::SetEncoding( rtl_TextEncoding eEnc )
678{
679 if (eEnc == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)))
680 eEnc = GetCodeSet();
681
682 if (!aParserStates.empty())
683 aParserStates.top().eCodeSet = eEnc;
684 SetSrcEncoding(eEnc);
685}
686
687/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

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#ifndef INCLUDED_TOOLS_REF_HXX
20#define INCLUDED_TOOLS_REF_HXX
21
22#include <sal/config.h>
23#include <cassert>
24#include <tools/toolsdllapi.h>
25#include <utility>
26
27/**
28 This implements similar functionality to boost::intrusive_ptr
29*/
30
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
36 SvRef(): pObj(nullptr) {}
37
38 SvRef(SvRef&& rObj) noexcept
39 {
40 pObj = rObj.pObj;
41 rObj.pObj = nullptr;
42 }
43
44 SvRef(SvRef const & rObj): pObj(rObj.pObj)
45 {
46 if (pObj != nullptr) pObj->AddNextRef();
47 }
48
49 SvRef(T * pObjP): pObj(pObjP)
50 {
51 if (pObj != nullptr) pObj->AddFirstRef();
52 }
53
54 ~SvRef()
55 {
56 if (pObj != nullptr) pObj->ReleaseRef();
57 }
58
59 void clear()
60 {
61 if (pObj != nullptr) {
62 T * pRefObj = pObj;
63 pObj = nullptr;
64 pRefObj->ReleaseRef();
65 }
66 }
67
68 SvRef & operator =(SvRef const & rObj)
69 {
70 if (rObj.pObj != nullptr) {
71 rObj.pObj->AddNextRef();
72 }
73 T * pRefObj = pObj;
74 pObj = rObj.pObj;
75 if (pRefObj != nullptr) {
76 pRefObj->ReleaseRef();
77 }
78 return *this;
79 }
80
81 SvRef & operator =(SvRef && rObj)
82 {
83 if (pObj != nullptr) {
84 pObj->ReleaseRef();
85 }
86 pObj = rObj.pObj;
87 rObj.pObj = nullptr;
88 return *this;
89 }
90
91 bool is() const { return pObj != nullptr; }
92
93 explicit operator bool() const { return is(); }
94
95 T * get() const { return pObj; }
96
97 T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 97, __extension__ __PRETTY_FUNCTION__))
; return pObj; }
98
99 T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
; return *pObj; }
100
101 bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; }
102 bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); }
103
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<T> make_ref(Args&& ... args)
113{
114 return SvRef<T>(new T(std::forward<Args>(args)...));
115}
116
117}
118
119/** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */
120class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase
121{
122 // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
123 // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
124 unsigned int nRefCount : 31;
125 // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
126 unsigned int bNoDelete : 1;
127
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
132 SvRefBase() : nRefCount(0), bNoDelete(1) {}
133 SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {}
134
135 SvRefBase & operator=(const SvRefBase &) { return *this; }
136
137 void RestoreNoDelete()
138 { bNoDelete = 1; }
139
140 void AddNextRef()
141 {
142 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
142, __extension__ __PRETTY_FUNCTION__))
;
143 ++nRefCount;
144 }
145
146 void AddFirstRef()
147 {
148 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
148, __extension__ __PRETTY_FUNCTION__))
;
149 if( bNoDelete )
150 bNoDelete = 0;
151 ++nRefCount;
152 }
153
154 void ReleaseRef()
155 {
156 assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail
("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 156, __extension__ __PRETTY_FUNCTION__))
;
7
Assuming field 'nRefCount' is >= 1
8
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete)
9
Assuming the condition is true
10
Assuming field 'bNoDelete' is 0
11
Taking true branch
158 {
159 // I'm not sure about the original purpose of this line, but right now
160 // it serves the purpose that anything that attempts to do an AddRef()
161 // after an object is deleted will trip an assert.
162 nRefCount = 1 << 30;
163 delete this;
12
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
185 void ResetWeakBase( ) { _pObj = nullptr; }
186 T* GetObj() { return _pObj; }
187};
188
189/** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame.
190 Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted.
191*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
198 /** Does not use initializer due to compiler warnings,
199 because the lifetime of the _xHdl object can exceed the lifetime of this class.
200 */
201 SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); }
202
203 ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); }
204
205 SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); }
206};
207
208/** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak.
209*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
215 SvCompatWeakRef( ) {}
216 SvCompatWeakRef( T* pObj )
217 { if( pObj ) _xHdl = pObj->GetHdl(); }
218#if defined(__COVERITY__)
219 ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {}
220#endif
221 SvCompatWeakRef& operator = ( T * pObj )
222 { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; }
223 bool is() const
224 { return _xHdl.is() && _xHdl->GetObj(); }
225 explicit operator bool() const { return is(); }
226 T* operator -> () const
227 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
228 operator T* () const
229 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
230};
231
232#endif
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */