File: | home/maarten/src/libreoffice/core/svtools/source/svrtf/parrtf.cxx |
Warning: | line 593, column 12 Use of memory after it is freed |
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 <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 | ||||
32 | const int MAX_STRING_LEN = 1024; | |||
33 | const 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 | ||||
38 | SvRTFParser::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 | ||||
49 | SvRTFParser::~SvRTFParser() | |||
50 | { | |||
51 | } | |||
52 | ||||
53 | ||||
54 | int 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 | ||||
283 | sal_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 | ||||
303 | void 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 | ||||
524 | short SvRTFParser::_inSkipGroup=0; | |||
525 | ||||
526 | void 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 | ||||
567 | void SvRTFParser::ReadUnknownData() { SkipGroup(); } | |||
568 | void SvRTFParser::ReadBitmapData() { SkipGroup(); } | |||
569 | ||||
570 | ||||
571 | SvParserState 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() ) | |||
| ||||
584 | { | |||
585 | AddFirstRef(); | |||
586 | Continue( 0 ); | |||
587 | if( SvParserState::Pending != eState ) | |||
588 | ReleaseRef(); // now parser is not needed anymore | |||
589 | } | |||
590 | else | |||
591 | eState = SvParserState::Error; | |||
592 | ||||
593 | return eState; | |||
| ||||
594 | } | |||
595 | ||||
596 | void 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: | |||
663 | NEXTTOKEN: | |||
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 | ||||
677 | void 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: */ |
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 | |
31 | namespace tools { |
32 | |
33 | /** T must be a class that extends SvRefBase */ |
34 | template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final { |
35 | public: |
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 | |
104 | private: |
105 | T * pObj; |
106 | }; |
107 | |
108 | /** |
109 | * This implements similar functionality to std::make_shared. |
110 | */ |
111 | template<typename T, typename... Args> |
112 | SvRef<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 */ |
120 | class 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 | |
128 | protected: |
129 | virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE; |
130 | |
131 | public: |
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__)); |
157 | if( --nRefCount == 0 && !bNoDelete) |
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; |
164 | } |
165 | } |
166 | |
167 | unsigned int GetRefCount() const |
168 | { return nRefCount; } |
169 | }; |
170 | |
171 | template<typename T> |
172 | class SvCompatWeakBase; |
173 | |
174 | /** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T. |
175 | */ |
176 | template<typename T> |
177 | class SvCompatWeakHdl final : public SvRefBase |
178 | { |
179 | friend class SvCompatWeakBase<T>; |
180 | T* _pObj; |
181 | |
182 | SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {} |
183 | |
184 | public: |
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 | */ |
192 | template<typename T> |
193 | class SvCompatWeakBase |
194 | { |
195 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; |
196 | |
197 | public: |
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 | */ |
210 | template<typename T> |
211 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef |
212 | { |
213 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; |
214 | public: |
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: */ |