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