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