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