bump product version to 4.1.6.2
[LibreOffice.git] / writerfilter / source / rtftok / rtftokenizer.cxx
blob873c7e98110561a1b5cc68b6cd21219bd9475413
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <tools/stream.hxx>
11 #include <tools/resmgr.hxx>
12 #include <svx/dialogs.hrc>
13 #include <vcl/svapp.hxx>
15 #include <rtftokenizer.hxx>
16 #include <rtfskipdestination.hxx>
19 namespace writerfilter {
20 namespace rtftok {
22 std::vector<RTFSymbol> RTFTokenizer::m_aRTFControlWords;
23 bool RTFTokenizer::m_bControlWordsSorted;
25 RTFTokenizer::RTFTokenizer(RTFDocumentImpl& rImport, SvStream* pInStream, uno::Reference<task::XStatusIndicator> const& xStatusIndicator)
26 : m_rImport(rImport),
27 m_pInStream(pInStream),
28 m_xStatusIndicator(xStatusIndicator),
29 m_nGroup(0),
30 m_nLineNumber(0),
31 m_nLineStartPos(0)
33 if (!RTFTokenizer::m_bControlWordsSorted)
35 RTFTokenizer::m_bControlWordsSorted = true;
36 m_aRTFControlWords = std::vector<RTFSymbol>(aRTFControlWords, aRTFControlWords + nRTFControlWords);
37 std::sort(m_aRTFControlWords.begin(), m_aRTFControlWords.end());
41 RTFTokenizer::~RTFTokenizer()
45 SvStream& RTFTokenizer::Strm()
47 return *m_pInStream;
50 int RTFTokenizer::resolveParse()
52 SAL_INFO( "writerfilter", OSL_THIS_FUNC );
53 char ch;
54 int ret;
55 // for hex chars
56 int b = 0, count = 2;
57 sal_uInt32 nPercentSize = 0;
58 sal_uInt32 nLastPos = 0;
60 if (m_xStatusIndicator.is())
62 static ResMgr* pResMgr = ResMgr::CreateResMgr("svx", Application::GetSettings().GetUILanguageTag());
63 OUString sDocLoad(ResId(RID_SVXSTR_DOC_LOAD, *pResMgr).toString());
65 sal_uInt32 nCurrentPos = Strm().Tell();
66 Strm().Seek(STREAM_SEEK_TO_END);
67 sal_uInt32 nEndPos = Strm().Tell();
68 Strm().Seek(nCurrentPos);
69 m_xStatusIndicator->start(sDocLoad, nEndPos);
70 nPercentSize = nEndPos / 100;
72 m_xStatusIndicator->setValue(nLastPos = nCurrentPos);
75 while ((Strm() >> ch, !Strm().IsEof()))
77 //SAL_INFO("writerfilter", OSL_THIS_FUNC << ": parsing character '" << ch << "'");
79 sal_uInt32 nCurrentPos = Strm().Tell();
80 if (m_xStatusIndicator.is() && nCurrentPos > (nLastPos + nPercentSize))
81 m_xStatusIndicator->setValue(nLastPos = nCurrentPos);
83 if (m_nGroup < 0)
84 return ERROR_GROUP_UNDER;
85 if (m_nGroup > 0 && m_rImport.getState().nInternalState == INTERNAL_BIN)
87 ret = m_rImport.resolveChars(ch);
88 if (ret)
89 return ret;
91 else
93 switch (ch)
95 case '{':
96 ret = m_rImport.pushState();
97 if (ret)
98 return ret;
99 break;
100 case '}':
101 ret = m_rImport.popState();
102 if (ret)
103 return ret;
104 if (m_nGroup == 0)
106 if (m_rImport.isSubstream())
107 m_rImport.finishSubstream();
108 return 0;
110 break;
111 case '\\':
112 ret = resolveKeyword();
113 if (ret)
114 return ret;
115 break;
116 case 0x0d:
117 break; // ignore this
118 case 0x0a:
119 m_nLineNumber++;
120 m_nLineStartPos = nCurrentPos;
121 break;
122 default:
123 if (m_nGroup == 0)
124 return ERROR_CHAR_OVER;
125 if (m_rImport.getState().nInternalState == INTERNAL_NORMAL)
127 ret = m_rImport.resolveChars(ch);
128 if (ret)
129 return ret;
131 else
133 SAL_INFO("writerfilter", OSL_THIS_FUNC << ": hex internal state");
134 b = b << 4;
135 sal_Int8 parsed = asHex(ch);
136 if (parsed == -1)
137 return ERROR_HEX_INVALID;
138 b += parsed;
139 count--;
140 if (!count)
142 ret = m_rImport.resolveChars(b);
143 if (ret)
144 return ret;
145 count = 2;
146 b = 0;
147 m_rImport.getState().nInternalState = INTERNAL_NORMAL;
150 break;
155 if (m_nGroup < 0)
156 return ERROR_GROUP_UNDER;
157 else if (m_nGroup > 0)
158 return ERROR_GROUP_OVER;
159 return 0;
162 int RTFTokenizer::asHex(char ch)
164 int ret = 0;
165 if (isdigit(ch))
166 ret = ch - '0';
167 else
169 if (islower(ch))
171 if (ch < 'a' || ch > 'f')
172 return -1;
173 ret = ch - 'a';
175 else
177 if (ch < 'A' || ch > 'F')
178 return -1;
179 ret = ch - 'A';
181 ret += 10;
183 return ret;
186 int RTFTokenizer::getGroup() const
188 return m_nGroup;
191 void RTFTokenizer::pushGroup()
193 m_nGroup++;
196 void RTFTokenizer::popGroup()
198 m_nGroup--;
201 int RTFTokenizer::resolveKeyword()
203 char ch;
204 OStringBuffer aBuf;
205 bool bNeg = false;
206 bool bParam = false;
207 int nParam = 0;
209 Strm() >> ch;
210 if (Strm().IsEof())
211 return ERROR_EOF;
213 if (!isalpha(ch))
215 aBuf.append(ch);
216 OString aKeyword = aBuf.makeStringAndClear();
217 // control symbols aren't followed by a space, so we can return here
218 // without doing any SeekRel()
219 return dispatchKeyword(aKeyword, bParam, nParam);
221 while(isalpha(ch))
223 aBuf.append(ch);
224 Strm() >> ch;
225 if (Strm().IsEof())
227 ch = ' ';
228 break;
231 if (aBuf.getLength() > 32)
232 // See RTF spec v1.9.1, page 7
233 // A control word's name cannot be longer than 32 letters.
234 throw io::BufferSizeExceededException();
236 if (ch == '-')
238 // in case we'll have a parameter, that will be negative
239 bNeg = true;
240 Strm() >> ch;
241 if (Strm().IsEof())
242 return ERROR_EOF;
244 if (isdigit(ch))
246 OStringBuffer aParameter;
248 // we have a parameter
249 bParam = true;
250 while(isdigit(ch))
252 aParameter.append(ch);
253 Strm() >> ch;
254 if (Strm().IsEof())
256 ch = ' ';
257 break;
260 nParam = aParameter.makeStringAndClear().toInt32();
261 if (bNeg)
262 nParam = -nParam;
264 if (ch != ' ')
265 Strm().SeekRel(-1);
266 OString aKeyword = aBuf.makeStringAndClear();
267 return dispatchKeyword(aKeyword, bParam, nParam);
270 int RTFTokenizer::dispatchKeyword(OString& rKeyword, bool bParam, int nParam)
272 if (m_rImport.getState().nDestinationState == DESTINATION_SKIP)
273 return 0;
274 /*SAL_INFO("writefilter", OSL_THIS_FUNC << ": keyword '\\" << rKeyword.getStr() <<
275 "' with param? " << (bParam ? 1 : 0) <<" param val: '" << (bParam ? nParam : 0) << "'");*/
276 RTFSymbol aSymbol;
277 aSymbol.sKeyword = rKeyword.getStr();
278 std::vector<RTFSymbol>::iterator low = std::lower_bound(m_aRTFControlWords.begin(), m_aRTFControlWords.end(), aSymbol);
279 int i = low - m_aRTFControlWords.begin();
280 if (low == m_aRTFControlWords.end() || aSymbol < *low)
282 SAL_INFO("writerfilter", OSL_THIS_FUNC << ": unknown keyword '\\" << rKeyword.getStr() << "'");
283 RTFSkipDestination aSkip(m_rImport);
284 aSkip.setParsed(false);
285 return 0;
288 int ret;
289 switch (m_aRTFControlWords[i].nControlType)
291 case CONTROL_FLAG:
292 // flags ignore any parameter by definition
293 ret = m_rImport.dispatchFlag(m_aRTFControlWords[i].nIndex);
294 if (ret)
295 return ret;
296 break;
297 case CONTROL_DESTINATION:
298 // same for destinations
299 ret = m_rImport.dispatchDestination(m_aRTFControlWords[i].nIndex);
300 if (ret)
301 return ret;
302 break;
303 case CONTROL_SYMBOL:
304 // and symbols
305 ret = m_rImport.dispatchSymbol(m_aRTFControlWords[i].nIndex);
306 if (ret)
307 return ret;
308 break;
309 case CONTROL_TOGGLE:
310 ret = m_rImport.dispatchToggle(m_aRTFControlWords[i].nIndex, bParam, nParam);
311 if (ret)
312 return ret;
313 break;
314 case CONTROL_VALUE:
315 // values require a parameter by definition
316 if (bParam) {
317 ret = m_rImport.dispatchValue(m_aRTFControlWords[i].nIndex, nParam);
318 if (ret)
319 return ret;
321 break;
324 return 0;
327 OUString RTFTokenizer::getPosition()
329 OUStringBuffer aRet;
330 aRet.append(m_nLineNumber + 1);
331 aRet.append(",");
332 aRet.append(sal_Int32(Strm().Tell() - m_nLineStartPos + 1));
333 return aRet.makeStringAndClear();
336 } // namespace rtftok
337 } // namespace writerfilter
339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */