Line data Source code
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 :
10 : #include <rtftokenizer.hxx>
11 : #include <svx/dialogs.hrc>
12 : #include <vcl/svapp.hxx>
13 : #include <rtl/strbuf.hxx>
14 : #include <rtfskipdestination.hxx>
15 : #include <com/sun/star/io/BufferSizeExceededException.hpp>
16 :
17 : using namespace com::sun::star;
18 :
19 : namespace writerfilter
20 : {
21 : namespace rtftok
22 : {
23 :
24 24 : std::vector<RTFSymbol> RTFTokenizer::m_aRTFControlWords;
25 : bool RTFTokenizer::m_bControlWordsSorted;
26 24 : std::vector<RTFMathSymbol> RTFTokenizer::m_aRTFMathControlWords;
27 : bool RTFTokenizer::m_bMathControlWordsSorted;
28 :
29 512 : RTFTokenizer::RTFTokenizer(RTFListener& rImport, SvStream* pInStream, uno::Reference<task::XStatusIndicator> const& xStatusIndicator)
30 : : m_rImport(rImport),
31 : m_pInStream(pInStream),
32 : m_xStatusIndicator(xStatusIndicator),
33 : m_nGroup(0),
34 : m_nLineNumber(0),
35 : m_nLineStartPos(0),
36 512 : m_nGroupStart(0)
37 : {
38 512 : if (!RTFTokenizer::m_bControlWordsSorted)
39 : {
40 6 : RTFTokenizer::m_bControlWordsSorted = true;
41 6 : m_aRTFControlWords = std::vector<RTFSymbol>(aRTFControlWords, aRTFControlWords + nRTFControlWords);
42 6 : std::sort(m_aRTFControlWords.begin(), m_aRTFControlWords.end());
43 : }
44 512 : if (!RTFTokenizer::m_bMathControlWordsSorted)
45 : {
46 6 : RTFTokenizer::m_bMathControlWordsSorted = true;
47 6 : m_aRTFMathControlWords = std::vector<RTFMathSymbol>(aRTFMathControlWords, aRTFMathControlWords + nRTFMathControlWords);
48 6 : std::sort(m_aRTFMathControlWords.begin(), m_aRTFMathControlWords.end());
49 : }
50 512 : }
51 :
52 1024 : RTFTokenizer::~RTFTokenizer()
53 : {
54 1024 : }
55 :
56 :
57 512 : RTFError RTFTokenizer::resolveParse()
58 : {
59 : SAL_INFO("writerfilter", OSL_THIS_FUNC);
60 : char ch;
61 : RTFError ret;
62 : // for hex chars
63 512 : int b = 0, count = 2;
64 512 : sal_uInt32 nPercentSize = 0;
65 512 : sal_uInt32 nLastPos = 0;
66 :
67 512 : if (m_xStatusIndicator.is())
68 : {
69 448 : static ResMgr* pResMgr = ResMgr::CreateResMgr("svx", Application::GetSettings().GetUILanguageTag());
70 448 : OUString sDocLoad(ResId(RID_SVXSTR_DOC_LOAD, *pResMgr).toString());
71 :
72 448 : sal_Size nCurrentPos = Strm().Tell();
73 448 : sal_Size nEndPos = nCurrentPos + Strm().remainingSize();
74 448 : m_xStatusIndicator->start(sDocLoad, nEndPos);
75 448 : nPercentSize = nEndPos / 100;
76 :
77 448 : m_xStatusIndicator->setValue(nLastPos = nCurrentPos);
78 : }
79 :
80 387880 : while ((Strm().ReadChar(ch), !Strm().IsEof()))
81 : {
82 : //SAL_INFO("writerfilter", OSL_THIS_FUNC << ": parsing character '" << ch << "'");
83 :
84 387365 : sal_Size nCurrentPos = Strm().Tell();
85 387365 : if (m_xStatusIndicator.is() && nCurrentPos > (nLastPos + nPercentSize))
86 20739 : m_xStatusIndicator->setValue(nLastPos = nCurrentPos);
87 :
88 387365 : if (m_nGroup < 0)
89 0 : return RTFError::GROUP_UNDER;
90 387365 : if (m_nGroup > 0 && m_rImport.getInternalState() == RTFInternalState::BIN)
91 : {
92 2 : ret = m_rImport.resolveChars(ch);
93 2 : if (ret != RTFError::OK)
94 0 : return ret;
95 : }
96 : else
97 : {
98 387363 : switch (ch)
99 : {
100 : case '{':
101 25949 : m_nGroupStart = Strm().Tell() - 1;
102 25949 : ret = m_rImport.pushState();
103 25949 : if (ret != RTFError::OK)
104 0 : return ret;
105 25949 : break;
106 : case '}':
107 25945 : ret = m_rImport.popState();
108 25945 : if (ret != RTFError::OK)
109 0 : return ret;
110 25945 : if (m_nGroup == 0)
111 : {
112 508 : if (m_rImport.isSubstream())
113 44 : m_rImport.finishSubstream();
114 508 : return RTFError::OK;
115 : }
116 25437 : break;
117 : case '\\':
118 223030 : ret = resolveKeyword();
119 223029 : if (ret != RTFError::OK)
120 0 : return ret;
121 223029 : break;
122 : case 0x0d:
123 7676 : break; // ignore this
124 : case 0x0a:
125 16887 : m_nLineNumber++;
126 16887 : m_nLineStartPos = nCurrentPos;
127 16887 : break;
128 : default:
129 87876 : if (m_nGroup == 0)
130 0 : return RTFError::CHAR_OVER;
131 87876 : if (m_rImport.getInternalState() == RTFInternalState::NORMAL)
132 : {
133 33250 : ret = m_rImport.resolveChars(ch);
134 33250 : if (ret != RTFError::OK)
135 0 : return ret;
136 : }
137 : else
138 : {
139 : SAL_INFO("writerfilter", OSL_THIS_FUNC << ": hex internal state");
140 54626 : b = b << 4;
141 54626 : sal_Int8 parsed = asHex(ch);
142 54626 : if (parsed == -1)
143 0 : return RTFError::HEX_INVALID;
144 54626 : b += parsed;
145 54626 : count--;
146 54626 : if (!count)
147 : {
148 27313 : ret = m_rImport.resolveChars(b);
149 27313 : if (ret != RTFError::OK)
150 0 : return ret;
151 27313 : count = 2;
152 27313 : b = 0;
153 27313 : m_rImport.setInternalState(RTFInternalState::NORMAL);
154 : }
155 : }
156 87876 : break;
157 : }
158 : }
159 : }
160 :
161 3 : if (m_nGroup < 0)
162 0 : return RTFError::GROUP_UNDER;
163 3 : else if (m_nGroup > 0)
164 3 : return RTFError::GROUP_OVER;
165 0 : return RTFError::OK;
166 : }
167 :
168 1895174 : int RTFTokenizer::asHex(char ch)
169 : {
170 1895174 : int ret = 0;
171 1895174 : if (isdigit(ch))
172 1135091 : ret = ch - '0';
173 : else
174 : {
175 760083 : if (islower(ch))
176 : {
177 760079 : if (ch < 'a' || ch > 'f')
178 0 : return -1;
179 760079 : ret = ch - 'a';
180 : }
181 : else
182 : {
183 4 : if (ch < 'A' || ch > 'F')
184 0 : return -1;
185 4 : ret = ch - 'A';
186 : }
187 760083 : ret += 10;
188 : }
189 1895174 : return ret;
190 : }
191 :
192 :
193 25949 : void RTFTokenizer::pushGroup()
194 : {
195 25949 : m_nGroup++;
196 25949 : }
197 :
198 25945 : void RTFTokenizer::popGroup()
199 : {
200 25945 : m_nGroup--;
201 25945 : }
202 :
203 223030 : RTFError RTFTokenizer::resolveKeyword()
204 : {
205 : char ch;
206 223030 : OStringBuffer aBuf;
207 223030 : bool bNeg = false;
208 223030 : bool bParam = false;
209 223030 : int nParam = 0;
210 :
211 223030 : Strm().ReadChar(ch);
212 223030 : if (Strm().IsEof())
213 0 : return RTFError::UNEXPECTED_EOF;
214 :
215 223030 : if (!isalpha(ch))
216 : {
217 39295 : aBuf.append(ch);
218 39295 : OString aKeyword = aBuf.makeStringAndClear();
219 : // control symbols aren't followed by a space, so we can return here
220 : // without doing any SeekRel()
221 39295 : return dispatchKeyword(aKeyword, bParam, nParam);
222 : }
223 1335799 : while (isalpha(ch))
224 : {
225 968330 : aBuf.append(ch);
226 968330 : Strm().ReadChar(ch);
227 968330 : if (Strm().IsEof())
228 : {
229 1 : ch = ' ';
230 1 : break;
231 : }
232 : }
233 183735 : if (aBuf.getLength() > 32)
234 : // See RTF spec v1.9.1, page 7
235 : // A control word's name cannot be longer than 32 letters.
236 1 : throw io::BufferSizeExceededException();
237 :
238 183734 : if (ch == '-')
239 : {
240 : // in case we'll have a parameter, that will be negative
241 2015 : bNeg = true;
242 2015 : Strm().ReadChar(ch);
243 2015 : if (Strm().IsEof())
244 0 : return RTFError::UNEXPECTED_EOF;
245 : }
246 183734 : if (isdigit(ch))
247 : {
248 111019 : OStringBuffer aParameter;
249 :
250 : // we have a parameter
251 111019 : bParam = true;
252 472216 : while (isdigit(ch))
253 : {
254 250178 : aParameter.append(ch);
255 250178 : Strm().ReadChar(ch);
256 250178 : if (Strm().IsEof())
257 : {
258 0 : ch = ' ';
259 0 : break;
260 : }
261 : }
262 111019 : nParam = aParameter.makeStringAndClear().toInt32();
263 111019 : if (bNeg)
264 2015 : nParam = -nParam;
265 : }
266 183734 : if (ch != ' ')
267 126819 : Strm().SeekRel(-1);
268 367468 : OString aKeyword = aBuf.makeStringAndClear();
269 406764 : return dispatchKeyword(aKeyword, bParam, nParam);
270 : }
271 :
272 2401 : bool RTFTokenizer::lookupMathKeyword(RTFMathSymbol& rSymbol)
273 : {
274 2401 : std::vector<RTFMathSymbol>::iterator low = std::lower_bound(m_aRTFMathControlWords.begin(), m_aRTFMathControlWords.end(), rSymbol);
275 2401 : int i = low - m_aRTFMathControlWords.begin();
276 2401 : if (low == m_aRTFMathControlWords.end() || rSymbol < *low)
277 1242 : return false;
278 1159 : rSymbol = m_aRTFMathControlWords[i];
279 1159 : return true;
280 : }
281 :
282 223029 : RTFError RTFTokenizer::dispatchKeyword(OString& rKeyword, bool bParam, int nParam)
283 : {
284 223029 : if (m_rImport.getDestination() == Destination::SKIP)
285 51089 : return RTFError::OK;
286 : SAL_INFO("writerfilter.rtf", OSL_THIS_FUNC << ": keyword '\\" << rKeyword.getStr() <<
287 : "' with param? " << (bParam ? 1 : 0) <<" param val: '" << (bParam ? nParam : 0) << "'");
288 : RTFSymbol aSymbol;
289 171940 : aSymbol.sKeyword = rKeyword.getStr();
290 171940 : std::vector<RTFSymbol>::iterator low = std::lower_bound(m_aRTFControlWords.begin(), m_aRTFControlWords.end(), aSymbol);
291 171940 : int i = low - m_aRTFControlWords.begin();
292 171940 : if (low == m_aRTFControlWords.end() || aSymbol < *low)
293 : {
294 : SAL_INFO("writerfilter", OSL_THIS_FUNC << ": unknown keyword '\\" << rKeyword.getStr() << "'");
295 468 : RTFSkipDestination aSkip(m_rImport);
296 468 : aSkip.setParsed(false);
297 468 : return RTFError::OK;
298 : }
299 :
300 : RTFError ret;
301 171472 : switch (m_aRTFControlWords[i].nControlType)
302 : {
303 : case CONTROL_FLAG:
304 : // flags ignore any parameter by definition
305 41094 : ret = m_rImport.dispatchFlag(m_aRTFControlWords[i].nIndex);
306 41094 : if (ret != RTFError::OK)
307 0 : return ret;
308 41094 : break;
309 : case CONTROL_DESTINATION:
310 : // same for destinations
311 13073 : ret = m_rImport.dispatchDestination(m_aRTFControlWords[i].nIndex);
312 13073 : if (ret != RTFError::OK)
313 0 : return ret;
314 13073 : break;
315 : case CONTROL_SYMBOL:
316 : // and symbols
317 33172 : ret = m_rImport.dispatchSymbol(m_aRTFControlWords[i].nIndex);
318 33172 : if (ret != RTFError::OK)
319 0 : return ret;
320 33172 : break;
321 : case CONTROL_TOGGLE:
322 2341 : ret = m_rImport.dispatchToggle(m_aRTFControlWords[i].nIndex, bParam, nParam);
323 2341 : if (ret != RTFError::OK)
324 0 : return ret;
325 2341 : break;
326 : case CONTROL_VALUE:
327 : // values require a parameter by definition
328 81792 : if (bParam)
329 : {
330 81201 : ret = m_rImport.dispatchValue(m_aRTFControlWords[i].nIndex, nParam);
331 81201 : if (ret != RTFError::OK)
332 0 : return ret;
333 : }
334 81792 : break;
335 : }
336 :
337 171472 : return RTFError::OK;
338 : }
339 :
340 3 : OUString RTFTokenizer::getPosition()
341 : {
342 3 : OUStringBuffer aRet;
343 3 : aRet.append(m_nLineNumber + 1);
344 3 : aRet.append(",");
345 3 : aRet.append(sal_Int32(Strm().Tell() - m_nLineStartPos + 1));
346 3 : return aRet.makeStringAndClear();
347 : }
348 :
349 :
350 : } // namespace rtftok
351 72 : } // namespace writerfilter
352 :
353 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|