Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "sal/config.h"
30 : :
31 : : #include "rtl/strbuf.hxx"
32 : : #include "rtl/string.hxx"
33 : : #include "rtl/ustrbuf.hxx"
34 : : #include "rtl/ustring.hxx"
35 : :
36 : : #include "tagtest.hxx"
37 : :
38 : : #if OSL_DEBUG_LEVEL > 1
39 : : #include <stdio.h>
40 : : #endif
41 : :
42 : : #include "gsicheck.hxx"
43 : : #include "helper.hxx"
44 : :
45 : : #define HAS_FLAG( nFlags, nFlag ) ( ( nFlags & nFlag ) != 0 )
46 : : #define SET_FLAG( nFlags, nFlag ) ( nFlags |= nFlag )
47 : : #define RESET_FLAG( nFlags, nFlag ) ( nFlags &= ~nFlag ) // ~ = Bitweises NOT
48 : :
49 : :
50 : :
51 : 0 : TokenInfo::TokenInfo( TokenId pnId, sal_Int32 nP, rtl::OUString const & paStr, ParserMessageList &rErrorList )
52 : : : bClosed(sal_False)
53 : : , bCloseTag(sal_False)
54 : : , bIsBroken(sal_False)
55 : : , bHasBeenFixed(sal_False)
56 : : , bDone(sal_False)
57 : : , aTokenString( paStr )
58 : : , nId( pnId )
59 : 0 : , nPos(nP)
60 : : {
61 : 0 : if ( nId == TAG_COMMONSTART || nId == TAG_COMMONEND )
62 : 0 : SplitTag( rErrorList );
63 : 0 : }
64 : :
65 : : enum tagcheck { TC_START, TC_HAS_TAG_NAME, TC_HAS_PROP_NAME_EQ, TC_HAS_PROP_NAME_EQ_SP, TC_HAS_PROP_NAME_SP, TC_INSIDE_STRING, TC_PROP_FINISHED, TC_CLOSED, TC_CLOSED_SPACE, TC_CLOSETAG, TC_CLOSETAG_HAS_TAG_NAME, TC_FINISHED, TC_ERROR };
66 : :
67 : : /*
68 : : \< link href = \"text\" name = \"C\" \>
69 : : START ' ' -> HAS_TAG_NAME
70 : : START '/' -> CLOSED
71 : : START '/' -> CLOSETAG - no Portion (starting with /)
72 : : START '>' -> FINISHED
73 : : HAS_TAG_NAME '=' -> HAS_PROP_NAME_EQ
74 : : HAS_TAG_NAME ' ' -> HAS_PROP_NAME_SP
75 : : HAS_TAG_NAME '/' -> CLOSED
76 : : HAS_TAG_NAME '>' -> FINISHED
77 : : HAS_PROP_NAME_SP '=' -> HAS_PROP_NAME_EQ
78 : : HAS_PROP_NAME_EQ ' ' -> HAS_PROP_NAME_EQ_SP
79 : : HAS_PROP_NAME_EQ '"' -> INSIDE_STRING
80 : : HAS_PROP_NAME_EQ_SP '"' -> INSIDE_STRING
81 : : INSIDE_STRING ' ' -> INSIDE_STRING
82 : : INSIDE_STRING '=' -> INSIDE_STRING
83 : : INSIDE_STRING '>' -> INSIDE_STRING
84 : : INSIDE_STRING '"' -> PROP_FINISHED
85 : : PROP_FINISHED ' ' -> HAS_TAG_NAME
86 : : PROP_FINISHED '/' -> CLOSED
87 : : PROP_FINISHED '>' -> FINISHED
88 : : CLOSED ' ' -> CLOSED_SPACE
89 : : CLOSED '>' -> FINISHED
90 : : CLOSED_SPACE '>' -> FINISHED
91 : :
92 : : CLOSETAG ' ' -> CLOSETAG_HAS_TAG_NAME
93 : : CLOSETAG '>' -> FINISHED
94 : : CLOSETAG_HAS_TAG_NAME '>' -> FINISHED
95 : :
96 : : */
97 : 0 : void TokenInfo::SplitTag( ParserMessageList &rErrorList )
98 : : {
99 : 0 : sal_Int32 nLastPos = 2; // skip initial \<
100 : 0 : sal_Int32 nCheckPos = nLastPos;
101 : : static char const aDelims[] = " \\=>/";
102 : 0 : rtl::OUString aPortion;
103 : 0 : rtl::OUString aValue; // store the value of a property
104 : 0 : rtl::OString aName; // store the name of a property/tag
105 : 0 : sal_Bool bCheckName = sal_False;
106 : 0 : sal_Bool bCheckEmpty = sal_False;
107 : : sal_Unicode cDelim;
108 : 0 : tagcheck aState = TC_START;
109 : :
110 : : // skip blanks
111 : 0 : while ( nLastPos < aTokenString.getLength() && aTokenString[nLastPos] == ' ')
112 : 0 : nLastPos++;
113 : :
114 : : nCheckPos = helper::indexOfAnyAsciiL(
115 : 0 : aTokenString, RTL_CONSTASCII_STRINGPARAM(aDelims), nLastPos);
116 : 0 : while ( nCheckPos != -1 && !( aState == TC_FINISHED || aState == TC_ERROR ) )
117 : : {
118 : 0 : aPortion = aTokenString.copy( nLastPos, nCheckPos-nLastPos );
119 : :
120 : 0 : if ( aTokenString[nCheckPos] == '\\' )
121 : 0 : nCheckPos++;
122 : :
123 : 0 : cDelim = aTokenString[nCheckPos];
124 : 0 : nCheckPos++;
125 : :
126 : 0 : switch ( aState )
127 : : {
128 : : // START ' ' -> HAS_TAG_NAME
129 : : // START '/' -> CLOSED
130 : : // START '>' -> FINISHED
131 : : case TC_START:
132 : 0 : aTagName = aPortion;
133 : 0 : switch ( cDelim )
134 : : {
135 : 0 : case ' ': aState = TC_HAS_TAG_NAME;
136 : 0 : bCheckName = sal_True;
137 : 0 : break;
138 : : case '/':
139 : : {
140 : 0 : if (aPortion.isEmpty())
141 : : {
142 : 0 : aState = TC_CLOSETAG;
143 : : }
144 : : else
145 : : {
146 : 0 : aState = TC_CLOSED;
147 : 0 : bCheckName = sal_True;
148 : : }
149 : : }
150 : 0 : break;
151 : 0 : case '>': aState = TC_FINISHED;
152 : 0 : bCheckName = sal_True;
153 : 0 : break;
154 : 0 : default: aState = TC_ERROR;
155 : : }
156 : 0 : break;
157 : :
158 : : // HAS_TAG_NAME '=' -> HAS_PROP_NAME_EQ
159 : : // HAS_TAG_NAME ' ' -> HAS_PROP_NAME_SP
160 : : // HAS_TAG_NAME '/' -> CLOSED
161 : : // HAS_TAG_NAME '>' -> FINISHED
162 : : case TC_HAS_TAG_NAME:
163 : 0 : switch ( cDelim )
164 : : {
165 : 0 : case '=': aState = TC_HAS_PROP_NAME_EQ;
166 : 0 : bCheckName = sal_True;
167 : 0 : break;
168 : 0 : case ' ': aState = TC_HAS_PROP_NAME_SP;
169 : 0 : bCheckName = sal_True;
170 : 0 : break;
171 : 0 : case '/': aState = TC_CLOSED;
172 : 0 : bCheckEmpty = sal_True;
173 : 0 : break;
174 : 0 : case '>': aState = TC_FINISHED;
175 : 0 : bCheckEmpty = sal_True;
176 : 0 : break;
177 : 0 : default: aState = TC_ERROR;
178 : : }
179 : 0 : break;
180 : :
181 : : // HAS_PROP_NAME_SP '=' -> HAS_PROP_NAME_EQ
182 : : case TC_HAS_PROP_NAME_SP:
183 : 0 : switch ( cDelim )
184 : : {
185 : 0 : case '=': aState = TC_HAS_PROP_NAME_EQ;
186 : 0 : bCheckEmpty = sal_True;
187 : 0 : break;
188 : 0 : default: aState = TC_ERROR;
189 : : }
190 : 0 : break;
191 : :
192 : : // HAS_PROP_NAME_EQ ' ' -> HAS_PROP_NAME_EQ_SP
193 : : // HAS_PROP_NAME_EQ '"' -> INSIDE_STRING
194 : : case TC_HAS_PROP_NAME_EQ:
195 : 0 : switch ( cDelim )
196 : : {
197 : 0 : case ' ': aState = TC_HAS_PROP_NAME_EQ_SP;
198 : 0 : bCheckEmpty = sal_True;
199 : 0 : break;
200 : 0 : case '\"': aState = TC_INSIDE_STRING;
201 : 0 : bCheckEmpty = sal_True;
202 : 0 : aValue = rtl::OUString();
203 : 0 : break;
204 : 0 : default: aState = TC_ERROR;
205 : : }
206 : 0 : break;
207 : :
208 : : // HAS_PROP_NAME_EQ_SP '"' -> INSIDE_STRING
209 : : case TC_HAS_PROP_NAME_EQ_SP:
210 : 0 : switch ( cDelim )
211 : : {
212 : 0 : case '\"': aState = TC_INSIDE_STRING;
213 : 0 : bCheckEmpty = sal_True;
214 : 0 : aValue = rtl::OUString();
215 : 0 : break;
216 : 0 : default: aState = TC_ERROR;
217 : : }
218 : 0 : break;
219 : :
220 : : // INSIDE_STRING * -> INSIDE_STRING
221 : : // INSIDE_STRING '"' -> PROP_FINISHED
222 : : case TC_INSIDE_STRING:
223 : 0 : switch ( cDelim )
224 : : {
225 : : case '\"':
226 : : {
227 : 0 : aState = TC_PROP_FINISHED;
228 : 0 : aValue += aPortion;
229 : 0 : if ( aProperties.find( aName ) == aProperties.end() )
230 : : {
231 : 0 : if ( !IsPropertyValueValid( aName, aValue ) )
232 : : {
233 : 0 : rErrorList.AddError( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Property '")).append(aName).append(RTL_CONSTASCII_STRINGPARAM("' has invalid value '")).append(rtl::OUStringToOString(aValue, RTL_TEXTENCODING_UTF8)).append("' ").makeStringAndClear(), *this );
234 : 0 : bIsBroken = sal_True;
235 : : }
236 : 0 : aProperties[ aName ] = aValue;
237 : : }
238 : : else
239 : : {
240 : 0 : rErrorList.AddError( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Property '")).append(aName).append(RTL_CONSTASCII_STRINGPARAM("' defined twice ")).makeStringAndClear(), *this );
241 : 0 : bIsBroken = sal_True;
242 : : }
243 : : }
244 : 0 : break;
245 : : default:
246 : : {
247 : 0 : aState = TC_INSIDE_STRING;
248 : 0 : aValue += aPortion;
249 : 0 : aValue += rtl::OUString(cDelim);
250 : : }
251 : : }
252 : 0 : break;
253 : :
254 : : // PROP_FINISHED ' ' -> HAS_TAG_NAME
255 : : // PROP_FINISHED '/' -> CLOSED
256 : : // PROP_FINISHED '>' -> FINISHED
257 : : case TC_PROP_FINISHED:
258 : 0 : switch ( cDelim )
259 : : {
260 : 0 : case ' ': aState = TC_HAS_TAG_NAME;
261 : 0 : bCheckEmpty = sal_True;
262 : 0 : break;
263 : 0 : case '/': aState = TC_CLOSED;
264 : 0 : bCheckEmpty = sal_True;
265 : 0 : break;
266 : 0 : case '>': aState = TC_FINISHED;
267 : 0 : bCheckEmpty = sal_True;
268 : 0 : break;
269 : 0 : default: aState = TC_ERROR;
270 : : }
271 : 0 : break;
272 : :
273 : : // CLOSED ' ' -> CLOSED_SPACE
274 : : // CLOSED '>' -> FINISHED
275 : : case TC_CLOSED:
276 : 0 : switch ( cDelim )
277 : : {
278 : 0 : case ' ': aState = TC_CLOSED_SPACE;
279 : 0 : bCheckEmpty = sal_True;
280 : 0 : bClosed = sal_True;
281 : 0 : break;
282 : 0 : case '>': aState = TC_FINISHED;
283 : 0 : bCheckEmpty = sal_True;
284 : 0 : break;
285 : 0 : default: aState = TC_ERROR;
286 : : }
287 : 0 : break;
288 : :
289 : : // CLOSED_SPACE '>' -> FINISHED
290 : : case TC_CLOSED_SPACE:
291 : 0 : switch ( cDelim )
292 : : {
293 : 0 : case '>': aState = TC_FINISHED;
294 : 0 : bCheckEmpty = sal_True;
295 : 0 : break;
296 : 0 : default: aState = TC_ERROR;
297 : : }
298 : 0 : break;
299 : :
300 : : // CLOSETAG ' ' -> CLOSETAG_HAS_TAG_NAME
301 : : // CLOSETAG '>' -> FINISHED
302 : : case TC_CLOSETAG:
303 : 0 : bCloseTag = sal_True;
304 : 0 : switch ( cDelim )
305 : : {
306 : 0 : case ' ': aState = TC_CLOSETAG_HAS_TAG_NAME;
307 : 0 : aTagName = aPortion;
308 : 0 : bCheckName = sal_True;
309 : 0 : break;
310 : 0 : case '>': aState = TC_FINISHED;
311 : 0 : aTagName = aPortion;
312 : 0 : bCheckName = sal_True;
313 : 0 : break;
314 : 0 : default: aState = TC_ERROR;
315 : : }
316 : 0 : break;
317 : :
318 : : // CLOSETAG_HAS_TAG_NAME '>' -> FINISHED
319 : : case TC_CLOSETAG_HAS_TAG_NAME:
320 : 0 : switch ( cDelim )
321 : : {
322 : 0 : case '>': aState = TC_FINISHED;
323 : 0 : bCheckEmpty = sal_True;
324 : 0 : break;
325 : 0 : default: aState = TC_ERROR;
326 : : }
327 : 0 : break;
328 : :
329 : :
330 : 0 : default: rErrorList.AddError( 99, "Internal error Parsing Tag ", *this );
331 : 0 : bIsBroken = sal_True;
332 : :
333 : : }
334 : :
335 : 0 : if ( bCheckName )
336 : : {
337 : 0 : if (aPortion.isEmpty())
338 : : {
339 : 0 : rErrorList.AddError( 25, "Tag/Property name missing ", *this );
340 : 0 : bIsBroken = sal_True;
341 : : }
342 : : else
343 : : {
344 : 0 : aName = rtl::OUStringToOString(aPortion, RTL_TEXTENCODING_UTF8);
345 : : // "a-zA-Z_-.0-9"
346 : 0 : sal_Bool bBroken = sal_False;
347 : 0 : const sal_Char* aBuf = aName.getStr();
348 : 0 : for (sal_Int32 nCount = 0 ; !bBroken && nCount < aName.getLength() ; ++nCount)
349 : : {
350 : 0 : bBroken = ! ( ( aBuf[nCount] >= 'a' && aBuf[nCount] <= 'z' )
351 : 0 : ||( aBuf[nCount] >= 'A' && aBuf[nCount] <= 'Z' )
352 : 0 : ||( aBuf[nCount] >= '0' && aBuf[nCount] <= '9' )
353 : 0 : ||( aBuf[nCount] == '_' )
354 : 0 : ||( aBuf[nCount] == '-' )
355 : 0 : ||( aBuf[nCount] == '.' )
356 : 0 : );
357 : : }
358 : :
359 : 0 : if ( bBroken )
360 : : {
361 : 0 : rErrorList.AddError( 25, "Found illegal character in Tag/Property name ", *this );
362 : 0 : bIsBroken = sal_True;
363 : : }
364 : : }
365 : :
366 : 0 : bCheckName = sal_False;
367 : : }
368 : :
369 : 0 : if ( bCheckEmpty )
370 : : {
371 : 0 : if (!aPortion.isEmpty())
372 : : {
373 : 0 : rErrorList.AddError( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Found displaced characters '")).append(rtl::OUStringToOString(aPortion, RTL_TEXTENCODING_UTF8)).append(RTL_CONSTASCII_STRINGPARAM("' in Tag ")).makeStringAndClear(), *this );
374 : 0 : bIsBroken = sal_True;
375 : : }
376 : 0 : bCheckEmpty = sal_False;
377 : : }
378 : :
379 : :
380 : 0 : nLastPos = nCheckPos;
381 : :
382 : : // skip further blanks
383 : 0 : if ( cDelim == ' ' && aState != TC_INSIDE_STRING )
384 : 0 : while ( nLastPos < aTokenString.getLength() && aTokenString[nLastPos] == ' ')
385 : 0 : nLastPos++;
386 : :
387 : : nCheckPos = helper::indexOfAnyAsciiL(
388 : 0 : aTokenString, RTL_CONSTASCII_STRINGPARAM(aDelims), nLastPos);
389 : : }
390 : 0 : if ( aState != TC_FINISHED )
391 : : {
392 : 0 : rErrorList.AddError( 25, "Parsing error in Tag ", *this );
393 : 0 : bIsBroken = sal_True;
394 : 0 : }
395 : 0 : }
396 : :
397 : 0 : sal_Bool TokenInfo::IsPropertyRelevant( const rtl::OString &rName, const rtl::OUString &rValue ) const
398 : : {
399 : 0 : if ( aTagName == "alt" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("xml-lang")) )
400 : 0 : return sal_False;
401 : 0 : if ( aTagName == "ahelp" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("visibility")) && rValue == "visible" )
402 : 0 : return sal_False;
403 : 0 : if ( aTagName == "image" && (rName.equalsL(RTL_CONSTASCII_STRINGPARAM("width")) || rName.equalsL(RTL_CONSTASCII_STRINGPARAM("height"))) )
404 : 0 : return sal_False;
405 : :
406 : 0 : return sal_True;
407 : : }
408 : :
409 : 0 : sal_Bool TokenInfo::IsPropertyValueValid( const rtl::OString &rName, const rtl::OUString &rValue ) const
410 : : {
411 : : /* removed due to i56740
412 : : if ( aTagName.EqualsAscii( "switchinline" ) && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("select")) )
413 : : {
414 : : return rValue.EqualsAscii("sys") ||
415 : : rValue.EqualsAscii("appl") ||
416 : : rValue.EqualsAscii("distrib");
417 : : } */
418 : 0 : if ( aTagName == "caseinline" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("select")) )
419 : : {
420 : 0 : return !rValue.isEmpty();
421 : : }
422 : :
423 : : // we don't know any better so we assume it to be OK
424 : 0 : return sal_True;
425 : : }
426 : :
427 : 0 : sal_Bool TokenInfo::IsPropertyInvariant( const rtl::OString &rName, const rtl::OUString &rValue ) const
428 : : {
429 : 0 : if ( aTagName == "link" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("name")) )
430 : 0 : return sal_False;
431 : 0 : if ( aTagName == "link" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("href")) )
432 : : { // check for external reference
433 : : return
434 : : !(rValue.matchIgnoreAsciiCaseAsciiL(
435 : 0 : RTL_CONSTASCII_STRINGPARAM("http:"))
436 : : || rValue.matchIgnoreAsciiCaseAsciiL(
437 : 0 : RTL_CONSTASCII_STRINGPARAM("https:"))
438 : : || rValue.matchIgnoreAsciiCaseAsciiL(
439 : 0 : RTL_CONSTASCII_STRINGPARAM("ftp:")));
440 : : }
441 : 0 : return sal_True;
442 : : }
443 : :
444 : 0 : sal_Bool TokenInfo::IsPropertyFixable( const rtl::OString &rName ) const
445 : : {
446 : : // name everything that is allowed to be fixed automatically here
447 : 0 : if ( (aTagName == "ahelp" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("hid")))
448 : 0 : || (aTagName == "link" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("href")))
449 : 0 : || (aTagName == "alt" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("id")))
450 : 0 : || (aTagName == "variable" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("id")))
451 : 0 : || (aTagName == "image" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("src")))
452 : 0 : || (aTagName == "image" && rName.equalsL(RTL_CONSTASCII_STRINGPARAM("id")) ))
453 : 0 : return sal_True;
454 : 0 : return sal_False;
455 : : }
456 : :
457 : 0 : sal_Bool TokenInfo::MatchesTranslation( TokenInfo& rInfo, sal_Bool bGenErrors, ParserMessageList &rErrorList, sal_Bool bFixTags ) const
458 : : {
459 : : // check if tags are equal
460 : : // check if all existing properties are in the translation as well and
461 : : // whether they have a matching content (the same in most cases)
462 : :
463 : 0 : if ( nId != rInfo.nId )
464 : 0 : return sal_False;
465 : :
466 : 0 : if ( aTagName != rInfo.aTagName )
467 : 0 : return sal_False;
468 : :
469 : : // If one of the tags has formating errors already it does make no sense to check here, so return right away
470 : 0 : if ( bGenErrors && ( bIsBroken || rInfo.bIsBroken ) )
471 : 0 : return sal_True;
472 : :
473 : 0 : StringHashMap::const_iterator iProp;
474 : 0 : for( iProp = aProperties.begin() ; iProp != aProperties.end(); ++iProp )
475 : : {
476 : 0 : if ( rInfo.aProperties.find( iProp->first ) != rInfo.aProperties.end() )
477 : : {
478 : 0 : if ( IsPropertyRelevant( iProp->first, iProp->second ) || IsPropertyRelevant( iProp->first, rInfo.aProperties.find( iProp->first )->second ) )
479 : : {
480 : 0 : if ( IsPropertyInvariant( iProp->first, iProp->second ) )
481 : : {
482 : 0 : if ( rInfo.aProperties.find( iProp->first )->second != iProp->second )
483 : : {
484 : 0 : if ( bGenErrors )
485 : : {
486 : 0 : if ( bFixTags && IsPropertyFixable( iProp->first ) )
487 : : {
488 : 0 : rInfo.aProperties.find( iProp->first )->second = iProp->second;
489 : 0 : rInfo.SetHasBeenFixed();
490 : 0 : rErrorList.AddWarning( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Property '")).append(iProp->first).append(RTL_CONSTASCII_STRINGPARAM("': FIXED different value in Translation ")).makeStringAndClear(), *this );
491 : : }
492 : : else
493 : 0 : rErrorList.AddError( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Property '")).append(iProp->first).append(RTL_CONSTASCII_STRINGPARAM("': value different in Translation ")).makeStringAndClear(), *this );
494 : : }
495 : 0 : else return sal_False;
496 : : }
497 : : }
498 : : }
499 : : }
500 : : else
501 : : {
502 : 0 : if ( IsPropertyRelevant( iProp->first, iProp->second ) )
503 : : {
504 : 0 : if ( bGenErrors )
505 : 0 : rErrorList.AddError( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Property '")).append(iProp->first).append(RTL_CONSTASCII_STRINGPARAM("' missing in Translation ")).makeStringAndClear(), *this );
506 : 0 : else return sal_False;
507 : : }
508 : : }
509 : : }
510 : 0 : for( iProp = rInfo.aProperties.begin() ; iProp != rInfo.aProperties.end(); ++iProp )
511 : : {
512 : 0 : if ( aProperties.find( iProp->first ) == aProperties.end() )
513 : : {
514 : 0 : if ( IsPropertyRelevant( iProp->first, iProp->second ) )
515 : : {
516 : 0 : if ( bGenErrors )
517 : 0 : rErrorList.AddError( 25, rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM("Extra Property '")).append(iProp->first).append(RTL_CONSTASCII_STRINGPARAM("' in Translation ")).makeStringAndClear(), rInfo );
518 : 0 : else return sal_False;
519 : : }
520 : : }
521 : : }
522 : :
523 : : // if we reach here eather
524 : : // the tags match completely or
525 : : // the tags match but not the properties and we generated errors for that
526 : 0 : return sal_True;
527 : : }
528 : :
529 : 0 : rtl::OUString TokenInfo::GetTagName() const
530 : : {
531 : 0 : return aTagName;
532 : : }
533 : :
534 : 0 : rtl::OUString TokenInfo::MakeTag() const
535 : : {
536 : 0 : rtl::OUStringBuffer aRet;
537 : 0 : aRet.appendAscii("\\<");
538 : 0 : if ( bCloseTag )
539 : 0 : aRet.appendAscii("/");
540 : 0 : aRet.append( GetTagName() );
541 : 0 : StringHashMap::const_iterator iProp;
542 : :
543 : 0 : for( iProp = aProperties.begin() ; iProp != aProperties.end(); ++iProp )
544 : : {
545 : 0 : aRet.appendAscii(" ");
546 : 0 : aRet.append( rtl::OStringToOUString( iProp->first, RTL_TEXTENCODING_UTF8 ) );
547 : 0 : aRet.appendAscii("=\\\"");
548 : 0 : aRet.append( iProp->second );
549 : 0 : aRet.appendAscii("\\\"");
550 : : }
551 : 0 : if ( bClosed )
552 : 0 : aRet.appendAscii("/");
553 : 0 : aRet.appendAscii("\\>");
554 : 0 : return aRet.makeStringAndClear();
555 : : }
556 : :
557 : :
558 : 0 : void ParserMessageList::AddError( sal_Int32 nErrorNr, const rtl::OString& rErrorText, const TokenInfo &rTag )
559 : : {
560 : 0 : maList.push_back( new ParserError( nErrorNr, rErrorText, rTag ) );
561 : 0 : }
562 : :
563 : 0 : void ParserMessageList::AddWarning( sal_Int32 nErrorNr, const rtl::OString& rErrorText, const TokenInfo &rTag )
564 : : {
565 : 0 : maList.push_back( new ParserWarning( nErrorNr, rErrorText, rTag ) );
566 : 0 : }
567 : :
568 : 0 : sal_Bool ParserMessageList::HasErrors()
569 : : {
570 : 0 : for ( size_t i = 0, n = maList.size(); i < n; ++i )
571 : 0 : if ( maList[ i ]->IsError() )
572 : 0 : return sal_True;
573 : 0 : return sal_False;
574 : : }
575 : :
576 : 0 : void ParserMessageList::clear()
577 : : {
578 : 0 : for ( size_t i = 0, n = maList.size(); i < n; ++i )
579 : 0 : delete maList[ i ];
580 : 0 : maList.clear();
581 : 0 : }
582 : :
583 : : struct Tag
584 : : {
585 : 0 : rtl::OUString GetName() const { return rtl::OUString::createFromAscii( pName ); };
586 : : const char* pName;
587 : : TokenId nTag;
588 : : };
589 : :
590 : :
591 : : static const Tag aKnownTags[] =
592 : : {
593 : : /* commenting oldstyle tags
594 : : // { "<#GROUP_FORMAT>", TAG_GROUP_FORMAT },
595 : : { "<#BOLD>", TAG_BOLDON },
596 : : { "<#/BOLD>", TAG_BOLDOFF },
597 : : { "<#ITALIC>", TAG_ITALICON },
598 : : { "<#/ITALIC>", TAG_ITALICOFF },
599 : : { "<#UNDER>", TAG_UNDERLINEON },
600 : : { "<#/UNDER>", TAG_UNDERLINEOFF },
601 : :
602 : : // { "<#GROUP_NOTALLOWED>", TAG_GROUP_NOTALLOWED },
603 : : { "<#HELPID>", TAG_HELPID },
604 : : { "<#MODIFY>", TAG_MODIFY },
605 : : { "<#REFNR>", TAG_REFNR },
606 : :
607 : : // { "<#GROUP_STRUCTURE>", TAG_GROUP_STRUCTURE },
608 : : { "<#NAME>", TAG_NAME },
609 : : { "<#HREF>", TAG_HREF },
610 : : { "<#AVIS>", TAG_AVIS },
611 : : { "<#AHID>", TAG_AHID },
612 : : { "<#AEND>", TAG_AEND },
613 : :
614 : : { "<#TITEL>", TAG_TITEL },
615 : : { "<#KEY>", TAG_KEY },
616 : : { "<#INDEX>", TAG_INDEX },
617 : :
618 : : { "<#REFSTART>", TAG_REFSTART },
619 : :
620 : : { "<#GRAPHIC>", TAG_GRAPHIC },
621 : : { "<#NEXTVERSION>", TAG_NEXTVERSION },
622 : :
623 : : // { "<#GROUP_SYSSWITCH>", TAG_GROUP_SYSSWITCH },
624 : : { "<#WIN>", TAG_WIN },
625 : : { "<#UNIX>", TAG_UNIX },
626 : : { "<#MAC>", TAG_MAC },
627 : : { "<#OS2>", TAG_OS2 },
628 : :
629 : : // { "<#GROUP_PROGSWITCH>", TAG_GROUP_PROGSWITCH },
630 : : { "<#WRITER>", TAG_WRITER },
631 : : { "<#CALC>", TAG_CALC },
632 : : { "<#DRAW>", TAG_DRAW },
633 : : { "<#IMPRESS>", TAG_IMPRESS },
634 : : { "<#SCHEDULE>", TAG_SCHEDULE },
635 : : { "<#IMAGE>", TAG_IMAGE },
636 : : { "<#MATH>", TAG_MATH },
637 : : { "<#CHART>", TAG_CHART },
638 : : { "<#OFFICE>", TAG_OFFICE },
639 : : */
640 : : // { "<#TAG_GROUP_META>", TAG_GROUP_META },
641 : : { "$[officefullname]", TAG_OFFICEFULLNAME },
642 : : { "$[officename]", TAG_OFFICENAME },
643 : : { "$[officepath]", TAG_OFFICEPATH },
644 : : { "$[officeversion]", TAG_OFFICEVERSION },
645 : : { "$[portalname]", TAG_PORTALNAME },
646 : : { "$[portalfullname]", TAG_PORTALFULLNAME },
647 : : { "$[portalpath]", TAG_PORTALPATH },
648 : : { "$[portalversion]", TAG_PORTALVERSION },
649 : : { "$[portalshortname]", TAG_PORTALSHORTNAME },
650 : : /* commenting oldstyle tags
651 : : // { "<#TAG_GROUP_SINGLE>", TAG_GROUP_SINGLE },
652 : : { "<#REFINSERT>", TAG_REFINSERT },
653 : :
654 : : // { "<#GROUP_MULTI>", TAG_GROUP_MULTI },
655 : : { "<#END>", TAG_END },
656 : : { "<#ELSE>", TAG_ELSE },
657 : : { "<#VERSIONEND>", TAG_VERSIONEND },
658 : : { "<#ENDGRAPHIC>", TAG_ENDGRAPHIC },*/
659 : : { "<Common Tag>", TAG_COMMONSTART },
660 : : { "</Common Tag>", TAG_COMMONEND },
661 : :
662 : : { "<no more tags>", TAG_NOMORETAGS },
663 : : { "", TAG_UNKNOWN_TAG },
664 : : };
665 : :
666 : :
667 : 0 : SimpleParser::SimpleParser()
668 : : : nPos( 0 )
669 : 0 : , aNextTag( TAG_NOMORETAGS, TOK_INVALIDPOS )
670 : : {
671 : 0 : }
672 : :
673 : 0 : void SimpleParser::Parse( rtl::OUString const & PaSource )
674 : : {
675 : 0 : aSource = PaSource;
676 : 0 : nPos = 0;
677 : 0 : aLastToken = rtl::OUString();
678 : 0 : aNextTag = TokenInfo( TAG_NOMORETAGS, TOK_INVALIDPOS );
679 : 0 : aTokenList.clear();
680 : 0 : };
681 : :
682 : 0 : TokenInfo SimpleParser::GetNextToken( ParserMessageList &rErrorList )
683 : : {
684 : 0 : TokenInfo aResult;
685 : 0 : sal_Int32 nTokenStartPos = 0;
686 : 0 : if ( aNextTag.nId != TAG_NOMORETAGS )
687 : : {
688 : 0 : aResult = aNextTag;
689 : 0 : aNextTag = TokenInfo( TAG_NOMORETAGS, TOK_INVALIDPOS );
690 : : }
691 : : else
692 : : {
693 : 0 : aLastToken = GetNextTokenString( rErrorList, nTokenStartPos );
694 : 0 : if ( aLastToken.isEmpty() )
695 : 0 : return TokenInfo( TAG_NOMORETAGS, TOK_INVALIDPOS );
696 : :
697 : : // do we have a \< ... \> style tag?
698 : 0 : if (aLastToken.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("\\<")))
699 : : {
700 : : // check for paired \" \"
701 : 0 : bool bEven = true;
702 : 0 : sal_Int32 nQuotePos = 0;
703 : : sal_Int32 nQuotedQuotesPos =
704 : 0 : aLastToken.indexOfAsciiL(RTL_CONSTASCII_STRINGPARAM("\\\""));
705 : : sal_Int32 nQuotedBackPos = aLastToken.indexOfAsciiL(
706 : 0 : RTL_CONSTASCII_STRINGPARAM("\\\\"));
707 : : // this is only to kick out quoted backslashes
708 : 0 : while (nQuotedQuotesPos != -1)
709 : : {
710 : 0 : if ( nQuotedBackPos != -1 && nQuotedBackPos <= nQuotedQuotesPos )
711 : 0 : nQuotePos = nQuotedBackPos+2;
712 : : else
713 : : {
714 : 0 : nQuotePos = nQuotedQuotesPos+2;
715 : 0 : bEven = !bEven;
716 : : }
717 : : nQuotedQuotesPos = aLastToken.indexOfAsciiL(
718 : 0 : RTL_CONSTASCII_STRINGPARAM("\\\""), nQuotePos);
719 : : nQuotedBackPos = aLastToken.indexOfAsciiL(
720 : 0 : RTL_CONSTASCII_STRINGPARAM("\\\\"), nQuotePos);
721 : : // this is only to kick out quoted backslashes
722 : : }
723 : 0 : if ( !bEven )
724 : : {
725 : 0 : rErrorList.AddError( 24, "Missing quotes ( \\\" ) in Tag", TokenInfo( TAG_UNKNOWN_TAG, nTokenStartPos, aLastToken ) );
726 : : }
727 : :
728 : : // check if we have an end-tag or a start-tag
729 : 0 : sal_Int32 nNonBlankStartPos = 2;
730 : 0 : while (aLastToken[nNonBlankStartPos] == ' ')
731 : 0 : nNonBlankStartPos++;
732 : 0 : if (aLastToken[nNonBlankStartPos] == '/')
733 : 0 : aResult = TokenInfo( TAG_COMMONEND, nTokenStartPos, aLastToken, rErrorList );
734 : : else
735 : : {
736 : 0 : aResult = TokenInfo( TAG_COMMONSTART, nTokenStartPos, aLastToken, rErrorList );
737 : 0 : sal_Int32 nNonBlankEndPos = aLastToken.getLength() - 3;
738 : 0 : while (aLastToken[nNonBlankEndPos] == ' ')
739 : 0 : nNonBlankEndPos--;
740 : 0 : if (aLastToken[nNonBlankEndPos] == '/')
741 : 0 : aNextTag = TokenInfo( TAG_COMMONEND, nTokenStartPos, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\\</")) + aResult.GetTagName() + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\\>")), rErrorList );
742 : : }
743 : : }
744 : : else
745 : : {
746 : 0 : sal_Int32 i = 0;
747 : 0 : while ( aKnownTags[i].nTag != TAG_UNKNOWN_TAG &&
748 : 0 : aLastToken != aKnownTags[i].GetName() )
749 : 0 : i++;
750 : 0 : aResult = TokenInfo( aKnownTags[i].nTag, nTokenStartPos );
751 : : }
752 : : }
753 : :
754 : 0 : if ( aResult.nId == TAG_UNKNOWN_TAG )
755 : 0 : aResult = TokenInfo( TAG_UNKNOWN_TAG, nTokenStartPos, aLastToken );
756 : 0 : aTokenList.insert( aResult );
757 : 0 : return aResult;
758 : : }
759 : :
760 : 0 : rtl::OUString SimpleParser::GetNextTokenString( ParserMessageList &rErrorList, sal_Int32 &rTagStartPos )
761 : : {
762 : : sal_Int32 nStyle2StartPos = aSource.indexOfAsciiL(
763 : 0 : RTL_CONSTASCII_STRINGPARAM("$["), nPos );
764 : : sal_Int32 nStyle3StartPos = aSource.indexOfAsciiL(
765 : 0 : RTL_CONSTASCII_STRINGPARAM("\\<"), nPos);
766 : : sal_Int32 nStyle4StartPos = aSource.indexOfAsciiL(
767 : 0 : RTL_CONSTASCII_STRINGPARAM("\\\\"), nPos);
768 : : // this is only to kick out quoted backslashes
769 : :
770 : 0 : rTagStartPos = 0;
771 : :
772 : 0 : if (nStyle2StartPos == -1 && nStyle3StartPos == -1)
773 : 0 : return rtl::OUString(); // no more tokens
774 : :
775 : 0 : if ( nStyle4StartPos != -1
776 : : && (nStyle2StartPos == -1 || nStyle4StartPos < nStyle2StartPos)
777 : : && (nStyle3StartPos == -1 || nStyle4StartPos < nStyle3StartPos ) )
778 : : // to make sure \\ is always handled first
779 : : { // Skip quoted Backslash
780 : 0 : nPos = nStyle4StartPos +2;
781 : 0 : return GetNextTokenString( rErrorList, rTagStartPos );
782 : : }
783 : :
784 : 0 : if ( nStyle2StartPos != -1 && ( nStyle3StartPos == -1 || nStyle2StartPos < nStyle3StartPos ) )
785 : : { // test for $[ ... ] style tokens
786 : 0 : sal_Int32 nEndPos = aSource.indexOf(']', nStyle2StartPos);
787 : 0 : if (nEndPos == -1)
788 : : { // Token is incomplete. Skip start and search for better ones
789 : 0 : nPos = nStyle2StartPos +2;
790 : 0 : return GetNextTokenString( rErrorList, rTagStartPos );
791 : : }
792 : 0 : nPos = nEndPos;
793 : 0 : rTagStartPos = nStyle2StartPos;
794 : 0 : return aSource.copy(nStyle2StartPos, nEndPos - nStyle2StartPos + 1);
795 : : }
796 : : else
797 : : { // test for \< ... \> style tokens
798 : : sal_Int32 nEndPos = aSource.indexOfAsciiL(
799 : 0 : RTL_CONSTASCII_STRINGPARAM("\\>"), nStyle3StartPos);
800 : : sal_Int32 nQuotedBackPos = aSource.indexOfAsciiL(
801 : 0 : RTL_CONSTASCII_STRINGPARAM("\\\\"), nStyle3StartPos);
802 : : // this is only to kick out quoted backslashes
803 : 0 : while (nQuotedBackPos <= nEndPos && nQuotedBackPos != -1)
804 : : {
805 : : nEndPos = aSource.indexOfAsciiL(
806 : 0 : RTL_CONSTASCII_STRINGPARAM("\\>"), nQuotedBackPos + 2);
807 : : nQuotedBackPos = aSource.indexOfAsciiL(
808 : 0 : RTL_CONSTASCII_STRINGPARAM("\\\\"), nQuotedBackPos + 2);
809 : : // this is only to kick out quoted backslashes
810 : : }
811 : 0 : if (nEndPos == -1)
812 : : { // Token is incomplete. Skip start and search for better ones
813 : 0 : nPos = nStyle3StartPos +2;
814 : 0 : rErrorList.AddError( 24, "Tag Start '\\<' without Tag End '\\>'", TokenInfo( TAG_UNKNOWN_TAG, nStyle3StartPos, helper::abbreviate(aSource, nStyle3StartPos - 10, 20) ) );
815 : 0 : return GetNextTokenString( rErrorList, rTagStartPos );
816 : : }
817 : : // check for paired quoted " --> \"sometext\"
818 : :
819 : 0 : nPos = nEndPos;
820 : 0 : rTagStartPos = nStyle3StartPos;
821 : 0 : return aSource.copy(nStyle3StartPos, nEndPos-nStyle3StartPos + 2);
822 : : }
823 : : }
824 : :
825 : 0 : rtl::OUString SimpleParser::GetLexem( TokenInfo const &aToken )
826 : : {
827 : 0 : if ( !aToken.aTokenString.isEmpty() )
828 : 0 : return aToken.aTokenString;
829 : : else
830 : : {
831 : 0 : sal_Int32 i = 0;
832 : 0 : while ( aKnownTags[i].nTag != TAG_UNKNOWN_TAG &&
833 : : aKnownTags[i].nTag != aToken.nId )
834 : 0 : i++;
835 : :
836 : 0 : return aKnownTags[i].GetName();
837 : : }
838 : : }
839 : :
840 : 0 : TokenParser::TokenParser()
841 : 0 : : pErrorList( NULL )
842 : 0 : {}
843 : :
844 : 0 : void TokenParser::Parse( const rtl::OUString &aCode, ParserMessageList* pList )
845 : : {
846 : 0 : pErrorList = pList;
847 : :
848 : : //Scanner initialisieren
849 : 0 : aParser.Parse( aCode );
850 : :
851 : : //erstes Symbol holen
852 : 0 : aTag = aParser.GetNextToken( *pErrorList );
853 : :
854 : 0 : nPfCaseOptions = 0;
855 : 0 : nAppCaseOptions = 0;
856 : 0 : bPfCaseActive = sal_False;
857 : 0 : bAppCaseActive = sal_False;
858 : :
859 : 0 : nActiveRefTypes = 0;
860 : :
861 : : //Ausfuehren der Start-Produktion
862 : 0 : Paragraph();
863 : :
864 : : //Es wurde nicht die ganze Kette abgearbeitet, bisher ist aber
865 : : //kein Fehler aufgetreten
866 : : //=> es wurde ein einleitendes Tag vergessen
867 : 0 : if ( aTag.nId != TAG_NOMORETAGS )
868 : : {
869 : 0 : switch ( aTag.nId )
870 : : {
871 : : case TAG_END:
872 : : {
873 : 0 : ParseError( 3, "Extra Tag <#END>. Switch or <#HREF> expected.", aTag );
874 : : }
875 : 0 : break;
876 : : case TAG_BOLDOFF:
877 : : {
878 : 0 : ParseError( 4, "<#BOLD> expected before <#/BOLD>.", aTag );
879 : : }
880 : 0 : break;
881 : : case TAG_ITALICOFF:
882 : : {
883 : 0 : ParseError( 5, "<#ITALIC> expected before <#/ITALIC>.", aTag );
884 : : }
885 : 0 : break;
886 : : case TAG_UNDERLINEOFF:
887 : : {
888 : 0 : ParseError( 17, "<#UNDER> expected before <#/UNDER>.", aTag );
889 : : }
890 : 0 : break;
891 : : case TAG_AEND:
892 : : {
893 : 0 : ParseError( 5, "Extra Tag <#AEND>. <#AVIS> or <#AHID> expected.", aTag );
894 : : }
895 : 0 : break;
896 : : case TAG_ELSE:
897 : : {
898 : 0 : ParseError( 16, "Application-tag or platform-tag expected before <#ELSE>.", aTag );
899 : : }
900 : 0 : break;
901 : : case TAG_UNKNOWN_TAG:
902 : : {
903 : 0 : ParseError( 6, "unknown Tag", aTag );
904 : : }
905 : 0 : break;
906 : : default:
907 : : {
908 : 0 : ParseError( 6, "unexpected Tag", aTag );
909 : : }
910 : : }
911 : : }
912 : 0 : pErrorList = NULL;
913 : 0 : }
914 : :
915 : 0 : void TokenParser::Paragraph()
916 : : {
917 : 0 : switch ( aTag.nId )
918 : : {
919 : : case TAG_GRAPHIC:
920 : : case TAG_NEXTVERSION:
921 : : {
922 : 0 : TagRef();
923 : 0 : Paragraph();
924 : : }
925 : 0 : break;
926 : : case TAG_AVIS:
927 : : case TAG_AHID:
928 : : {
929 : 0 : TagRef();
930 : 0 : Paragraph();
931 : : }
932 : 0 : break;
933 : : case TAG_HELPID:
934 : : {
935 : 0 : SimpleTag();
936 : 0 : Paragraph();
937 : : }
938 : 0 : break;
939 : : case TAG_OFFICEFULLNAME:
940 : : case TAG_OFFICENAME:
941 : : case TAG_OFFICEPATH:
942 : : case TAG_OFFICEVERSION:
943 : : case TAG_PORTALNAME:
944 : : case TAG_PORTALFULLNAME:
945 : : case TAG_PORTALPATH:
946 : : case TAG_PORTALVERSION:
947 : : case TAG_PORTALSHORTNAME:
948 : : {
949 : 0 : SimpleTag();
950 : 0 : Paragraph();
951 : : }
952 : 0 : break;
953 : : case TAG_REFINSERT:
954 : : {
955 : 0 : SimpleTag();
956 : 0 : Paragraph();
957 : : }
958 : 0 : break;
959 : : case TAG_BOLDON:
960 : : case TAG_ITALICON:
961 : : case TAG_UNDERLINEON:
962 : : case TAG_COMMONSTART:
963 : : {
964 : 0 : TagPair();
965 : 0 : Paragraph();
966 : : }
967 : 0 : break;
968 : : case TAG_HREF:
969 : : case TAG_NAME:
970 : : case TAG_KEY:
971 : : case TAG_INDEX:
972 : : case TAG_TITEL:
973 : : case TAG_REFSTART:
974 : : {
975 : 0 : TagRef();
976 : 0 : Paragraph();
977 : : }
978 : 0 : break;
979 : : case TAG_WIN:
980 : : case TAG_UNIX:
981 : : case TAG_MAC: //...
982 : : {
983 : 0 : if ( ! bPfCaseActive )
984 : : {
985 : : //PfCases duerfen nicht verschachtelt sein:
986 : 0 : bPfCaseActive = sal_True;
987 : 0 : PfCase();
988 : :
989 : : //So jetzt kann wieder ein PfCase kommen:
990 : 0 : bPfCaseActive = sal_False;
991 : 0 : Paragraph();
992 : : }
993 : : }
994 : 0 : break;
995 : : case TAG_WRITER:
996 : : case TAG_CALC:
997 : : case TAG_DRAW:
998 : : case TAG_IMPRESS:
999 : : case TAG_SCHEDULE:
1000 : : case TAG_IMAGE:
1001 : : case TAG_MATH:
1002 : : case TAG_CHART:
1003 : : case TAG_OFFICE:
1004 : : {
1005 : 0 : if ( !bAppCaseActive )
1006 : : {
1007 : : //AppCases duerfen nicht verschachtelt sein:
1008 : 0 : bAppCaseActive = sal_True;
1009 : 0 : AppCase();
1010 : :
1011 : : //jetzt koennen wieder AppCases kommen:
1012 : 0 : bAppCaseActive = sal_False;
1013 : 0 : Paragraph();
1014 : : }
1015 : : }
1016 : 0 : break;
1017 : :
1018 : : //Case TAG_BOLDOFF, TAG_ITALICOFF, TAG_BUNDERLINE, TAG_END
1019 : : //nichts tun wg. epsilon-Prod.
1020 : : }
1021 : 0 : }
1022 : :
1023 : 0 : void TokenParser::PfCase()
1024 : : {
1025 : :
1026 : : //Produktion:
1027 : : //PfCase -> PfCaseBegin Paragraph (PfCase | PfCaseEnd)
1028 : :
1029 : 0 : PfCaseBegin();
1030 : :
1031 : : //Jetzt ist eine PfCase-Produktion aktiv:
1032 : 0 : Paragraph();
1033 : 0 : switch ( aTag.nId )
1034 : : {
1035 : : case TAG_ELSE:
1036 : : case TAG_END:
1037 : : {
1038 : 0 : CaseEnd();
1039 : : }
1040 : 0 : break;
1041 : : case TAG_WIN:
1042 : : case TAG_UNIX:
1043 : : case TAG_MAC: //First (PfBegin)
1044 : : {
1045 : 0 : PfCase();
1046 : : }
1047 : 0 : break;
1048 : : default:
1049 : 0 : ParseError( 8, "<#ELSE> or <#END> or platform-tag expected.", aTag );
1050 : : }
1051 : : //Die gemerkten Tags wieder loeschen fuer naechstes PfCase:
1052 : 0 : nPfCaseOptions = 0;
1053 : 0 : }
1054 : :
1055 : 0 : void TokenParser::PfCaseBegin()
1056 : : {
1057 : 0 : switch ( aTag.nId )
1058 : : {
1059 : : case TAG_WIN:
1060 : : case TAG_UNIX:
1061 : : case TAG_MAC:
1062 : : {
1063 : : //Token darf noch nicht vorgekommen sein im
1064 : : //aktuellen Plattform-Case:
1065 : 0 : if ( !HAS_FLAG( nPfCaseOptions, TAG_NOGROUP( aTag.nId ) ) )
1066 : : {
1067 : 0 : SET_FLAG( nPfCaseOptions, TAG_NOGROUP( aTag.nId ) );
1068 : 0 : match( aTag, aTag );
1069 : : }
1070 : : else {
1071 : 0 : ParseError( 9, "Tag defined twice in the same platform-case", aTag );
1072 : : }
1073 : : }
1074 : : }
1075 : 0 : }
1076 : :
1077 : 0 : void TokenParser::AppCase()
1078 : : {
1079 : :
1080 : : //Produktion:
1081 : : //AppCase -> AppCaseBegin Paragraph (AppCase | AppCaseEnd)
1082 : :
1083 : :
1084 : 0 : AppCaseBegin();
1085 : :
1086 : 0 : Paragraph();
1087 : :
1088 : 0 : switch ( aTag.nId )
1089 : : {
1090 : : case TAG_ELSE:
1091 : : case TAG_END:
1092 : : {
1093 : 0 : CaseEnd();
1094 : : }
1095 : 0 : break;
1096 : : case TAG_WRITER:
1097 : : case TAG_DRAW:
1098 : : case TAG_CALC:
1099 : : case TAG_IMAGE:
1100 : : case TAG_MATH:
1101 : : case TAG_CHART:
1102 : : case TAG_OFFICE:
1103 : : case TAG_IMPRESS:
1104 : : case TAG_SCHEDULE: //First (AppBegin)
1105 : : {
1106 : 0 : AppCase();
1107 : : }
1108 : 0 : break;
1109 : : default:
1110 : 0 : ParseError( 1, "<#ELSE> or <#END> or application-case-tag expected.", aTag );
1111 : : }
1112 : :
1113 : : //Die gemerkten Tags wieder loeschen fuer naechstes AppCase:
1114 : 0 : nAppCaseOptions = 0;
1115 : 0 : }
1116 : :
1117 : 0 : void TokenParser::AppCaseBegin()
1118 : : {
1119 : 0 : switch ( aTag.nId )
1120 : : {
1121 : : case TAG_WRITER:
1122 : : case TAG_DRAW:
1123 : : case TAG_CALC:
1124 : : case TAG_IMAGE:
1125 : : case TAG_MATH:
1126 : : case TAG_CHART:
1127 : : case TAG_OFFICE:
1128 : : case TAG_IMPRESS:
1129 : : case TAG_SCHEDULE:
1130 : : {
1131 : : //Token darf noch nicht vorgekommen sein im
1132 : : //aktuellen Plattform-Case:
1133 : 0 : if ( !HAS_FLAG( nAppCaseOptions, TAG_NOGROUP( aTag.nId ) ) )
1134 : : {
1135 : 0 : SET_FLAG( nAppCaseOptions, TAG_NOGROUP( aTag.nId ) );
1136 : 0 : match( aTag, aTag );
1137 : : }
1138 : : else {
1139 : 0 : ParseError( 13, "Tag defined twice in the same application-case.", aTag );
1140 : : }
1141 : : }
1142 : : }
1143 : 0 : }
1144 : :
1145 : 0 : void TokenParser::CaseEnd()
1146 : : {
1147 : : //Produktion:
1148 : : //CaseEnd -> <#ELSE> Paragraph <#END> | <#END>
1149 : :
1150 : 0 : switch ( aTag.nId )
1151 : : {
1152 : : case TAG_ELSE:
1153 : : {
1154 : 0 : match( aTag, TAG_ELSE );
1155 : 0 : Paragraph();
1156 : 0 : match( aTag, TAG_END );
1157 : : }
1158 : 0 : break;
1159 : : case TAG_END:
1160 : : {
1161 : 0 : match( aTag, TAG_END );
1162 : : }
1163 : 0 : break;
1164 : : default:
1165 : 0 : ParseError( 2, "<#ELSE> or <#END> expected.", aTag );
1166 : : }
1167 : 0 : }
1168 : :
1169 : 0 : void TokenParser::SimpleTag()
1170 : : {
1171 : :
1172 : 0 : switch ( aTag.nId )
1173 : : {
1174 : : case TAG_HELPID:
1175 : : {
1176 : 0 : match( aTag, TAG_HELPID );
1177 : : }
1178 : 0 : break;
1179 : : case TAG_OFFICEFULLNAME:
1180 : : case TAG_OFFICENAME:
1181 : : case TAG_OFFICEPATH:
1182 : : case TAG_OFFICEVERSION:
1183 : : case TAG_PORTALNAME:
1184 : : case TAG_PORTALFULLNAME:
1185 : : case TAG_PORTALPATH:
1186 : : case TAG_PORTALVERSION:
1187 : : case TAG_PORTALSHORTNAME:
1188 : :
1189 : : case TAG_REFINSERT:
1190 : : {
1191 : 0 : match( aTag, aTag );
1192 : : }
1193 : 0 : break;
1194 : : default:
1195 : 0 : ParseError( 15, "[<#SimpleTag>] expected.", aTag );
1196 : : }
1197 : 0 : }
1198 : :
1199 : 0 : void TokenParser::TagPair()
1200 : : {
1201 : 0 : switch ( aTag.nId )
1202 : : {
1203 : : case TAG_BOLDON:
1204 : : {
1205 : 0 : match( aTag, TAG_BOLDON );
1206 : 0 : Paragraph();
1207 : 0 : match( aTag, TAG_BOLDOFF );
1208 : : }
1209 : 0 : break;
1210 : : case TAG_ITALICON:
1211 : : {
1212 : 0 : match( aTag, TAG_ITALICON );
1213 : 0 : Paragraph();
1214 : 0 : match( aTag, TAG_ITALICOFF );
1215 : : }
1216 : 0 : break;
1217 : : case TAG_UNDERLINEON:
1218 : : {
1219 : 0 : match( aTag, TAG_UNDERLINEON );
1220 : 0 : Paragraph();
1221 : 0 : match( aTag, TAG_UNDERLINEOFF );
1222 : : }
1223 : 0 : break;
1224 : : case TAG_COMMONSTART:
1225 : : {
1226 : : //remember tag so we can give the original tag in case of an error
1227 : 0 : TokenInfo aEndTag( aTag );
1228 : 0 : aEndTag.nId = TAG_COMMONEND;
1229 : 0 : match( aTag, TAG_COMMONSTART );
1230 : 0 : Paragraph();
1231 : 0 : match( aTag, aEndTag );
1232 : : }
1233 : 0 : break;
1234 : : default:
1235 : 0 : ParseError( 10, "<#BOLD>, <#ITALIC>, <#UNDER> expected.", aTag );
1236 : : }
1237 : 0 : }
1238 : :
1239 : :
1240 : 0 : void TokenParser::TagRef()
1241 : : {
1242 : 0 : switch ( aTag.nId )
1243 : : {
1244 : : case TAG_GRAPHIC:
1245 : : case TAG_NEXTVERSION:
1246 : : {
1247 : 0 : if ( !HAS_FLAG( nActiveRefTypes, TAG_NOGROUP( aTag.nId ) ) )
1248 : : {
1249 : 0 : TokenId aThisToken = aTag.nId;
1250 : 0 : SET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) );
1251 : 0 : match( aTag, aTag );
1252 : 0 : Paragraph();
1253 : 0 : if ( aThisToken == TAG_GRAPHIC )
1254 : 0 : match( aTag, TAG_ENDGRAPHIC );
1255 : : else
1256 : 0 : match( aTag, TAG_VERSIONEND );
1257 : : // don't reset since alowed only once per paragraph
1258 : : // RESET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) );
1259 : : }
1260 : : else
1261 : : {
1262 : 0 : ParseError( 11, "Tags <#GRAPHIC>,<#NEXTVERSION> allowed only once per paragraph at", aTag );
1263 : : }
1264 : : }
1265 : 0 : break;
1266 : : case TAG_AVIS:
1267 : : case TAG_AHID:
1268 : : {
1269 : 0 : if ( !HAS_FLAG( nActiveRefTypes, TAG_NOGROUP( aTag.nId ) ) )
1270 : : {
1271 : 0 : TokenId aThisToken = aTag.nId;
1272 : 0 : SET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) );
1273 : 0 : match( aTag, aTag );
1274 : 0 : Paragraph();
1275 : 0 : match( aTag, TAG_AEND );
1276 : 0 : RESET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) );
1277 : : }
1278 : : else
1279 : : {
1280 : 0 : ParseError( 11, "Nested <#AHID>,<#AVIS> not allowed.", aTag );
1281 : : }
1282 : : }
1283 : 0 : break;
1284 : : case TAG_HREF:
1285 : : case TAG_NAME:
1286 : : {
1287 : :
1288 : : }
1289 : : // NOBREAK
1290 : : case TAG_KEY:
1291 : : case TAG_INDEX:
1292 : : case TAG_TITEL:
1293 : : case TAG_REFSTART:
1294 : : {
1295 : 0 : if ( !HAS_FLAG( nActiveRefTypes, TAG_NOGROUP( aTag.nId ) ) )
1296 : : {
1297 : 0 : TokenId aThisToken = aTag.nId;
1298 : 0 : match( aTag, aTag );
1299 : 0 : if ( aThisToken != TAG_NAME )
1300 : : { // TAG_NAME has no TAG_END
1301 : 0 : SET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) );
1302 : 0 : Paragraph();
1303 : 0 : match( aTag, TAG_END );
1304 : 0 : RESET_FLAG( nActiveRefTypes, TAG_NOGROUP( aThisToken ) );
1305 : : }
1306 : : }
1307 : : else
1308 : : {
1309 : 0 : ParseError( 11, "Nested <#HREF>,<#NAME> or <#KEY> not allowed.", aTag );
1310 : : }
1311 : : }
1312 : 0 : break;
1313 : : default:
1314 : 0 : ParseError( 12, "<#HREF>,<#NAME> or <#KEY> expected.", aTag );
1315 : : }
1316 : 0 : }
1317 : :
1318 : 0 : sal_Bool TokenParser::match( const TokenInfo &aCurrentToken, const TokenId &aExpectedToken )
1319 : : {
1320 : 0 : return match( aCurrentToken, TokenInfo( aExpectedToken, TOK_INVALIDPOS ) );
1321 : : }
1322 : :
1323 : 0 : sal_Bool TokenParser::match( const TokenInfo &aCurrentToken, const TokenInfo &rExpectedToken )
1324 : : {
1325 : 0 : TokenInfo aExpectedToken( rExpectedToken );
1326 : 0 : if ( aCurrentToken.nId == aExpectedToken.nId )
1327 : : {
1328 : 0 : if ( ( aCurrentToken.nId == TAG_COMMONEND
1329 : 0 : && aCurrentToken.GetTagName() == aExpectedToken.GetTagName() )
1330 : : || aCurrentToken.nId != TAG_COMMONEND )
1331 : : {
1332 : 0 : aTag = aParser.GetNextToken( *pErrorList );
1333 : 0 : return sal_True;
1334 : : }
1335 : : }
1336 : :
1337 : 0 : if ( aExpectedToken.nId == TAG_COMMONEND )
1338 : : {
1339 : : aExpectedToken.aTokenString =
1340 : : rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Close tag for "))
1341 : 0 : + aExpectedToken.aTokenString;
1342 : : }
1343 : :
1344 : 0 : rtl::OString sTmp(RTL_CONSTASCII_STRINGPARAM("Expected Symbol"));
1345 : 0 : if ( aCurrentToken.nId == TAG_NOMORETAGS )
1346 : : {
1347 : 0 : ParseError( 7, sTmp, aExpectedToken );
1348 : : }
1349 : : else
1350 : : {
1351 : 0 : rtl::OStringBuffer aBuf(sTmp);
1352 : 0 : aBuf.append(": ").
1353 : 0 : append(rtl::OUStringToOString(aParser.GetLexem( aExpectedToken ), RTL_TEXTENCODING_UTF8)).
1354 : 0 : append(RTL_CONSTASCII_STRINGPARAM(" near "));
1355 : 0 : ParseError( 7, aBuf.makeStringAndClear(), aCurrentToken );
1356 : : }
1357 : 0 : return sal_False;
1358 : : }
1359 : :
1360 : 0 : void TokenParser::ParseError( sal_Int32 nErrNr, const rtl::OString &rErrMsg, const TokenInfo &rTag )
1361 : : {
1362 : 0 : pErrorList->AddError( nErrNr, rErrMsg, rTag);
1363 : :
1364 : : // Das Fehlerhafte Tag ueberspringen
1365 : 0 : aTag = aParser.GetNextToken( *pErrorList );
1366 : 0 : }
1367 : :
1368 : :
1369 : 0 : ParserMessage::ParserMessage( sal_Int32 PnErrorNr, const rtl::OString &rPaErrorText, const TokenInfo &rTag )
1370 : : : nErrorNr( PnErrorNr )
1371 : : , nTagBegin( 0 )
1372 : 0 : , nTagLength( 0 )
1373 : : {
1374 : 0 : rtl::OUString aLexem( SimpleParser::GetLexem( rTag ) );
1375 : 0 : rtl::OStringBuffer aErrorBuffer(rPaErrorText);
1376 : 0 : aErrorBuffer.append(RTL_CONSTASCII_STRINGPARAM(": "));
1377 : 0 : aErrorBuffer.append(rtl::OUStringToOString(aLexem, RTL_TEXTENCODING_UTF8));
1378 : 0 : if ( rTag.nId == TAG_NOMORETAGS )
1379 : 0 : aErrorBuffer.append(RTL_CONSTASCII_STRINGPARAM(" at end of line "));
1380 : 0 : else if ( rTag.nPos != TOK_INVALIDPOS )
1381 : : {
1382 : 0 : aErrorBuffer.append(RTL_CONSTASCII_STRINGPARAM(" at Position "));
1383 : 0 : aErrorBuffer.append(static_cast<sal_Int32>(rTag.nPos));
1384 : : }
1385 : 0 : aErrorText = aErrorBuffer.makeStringAndClear();
1386 : 0 : nTagBegin = rTag.nPos;
1387 : 0 : nTagLength = aLexem.getLength();
1388 : 0 : }
1389 : :
1390 : 0 : ParserError::ParserError( sal_Int32 ErrorNr, const rtl::OString &rErrorText, const TokenInfo &rTag )
1391 : 0 : : ParserMessage( ErrorNr, rErrorText, rTag )
1392 : 0 : {}
1393 : :
1394 : 0 : ParserWarning::ParserWarning( sal_Int32 ErrorNr, const rtl::OString &rErrorText, const TokenInfo &rTag )
1395 : 0 : : ParserMessage( ErrorNr, rErrorText, rTag )
1396 : 0 : {}
1397 : :
1398 : 0 : sal_Bool LingTest::IsTagMandatory( TokenInfo const &aToken, TokenId &aMetaTokens )
1399 : : {
1400 : 0 : TokenId aTokenId = aToken.nId;
1401 : 0 : TokenId aTokenGroup = TAG_GROUP( aTokenId );
1402 : 0 : if ( TAG_GROUP_PROGSWITCH == aTokenGroup
1403 : : || TAG_REFINSERT == aTokenId
1404 : : || TAG_REFSTART == aTokenId
1405 : : || TAG_NAME == aTokenId
1406 : : || TAG_HREF == aTokenId
1407 : : || TAG_AVIS == aTokenId
1408 : : || TAG_AHID == aTokenId
1409 : : || TAG_GRAPHIC == aTokenId
1410 : : || TAG_NEXTVERSION == aTokenId
1411 : : || ( TAG_GROUP_META == aTokenGroup && (aMetaTokens & aTokenId) == aTokenId ) )
1412 : : {
1413 : 0 : if ( TAG_GROUP_META == aTokenGroup )
1414 : 0 : aMetaTokens |= aTokenId;
1415 : 0 : return sal_True;
1416 : : }
1417 : 0 : else if ( TAG_COMMONSTART == aTokenId
1418 : : || TAG_COMMONEND == aTokenId )
1419 : : {
1420 : 0 : rtl::OUString aTagName = aToken.GetTagName();
1421 : 0 : return !(aTagName.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("comment"))
1422 : 0 : || aTagName.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("bookmark_value"))
1423 : 0 : || aTagName.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("emph"))
1424 : 0 : || aTagName.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("item"))
1425 : 0 : || aTagName.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("br")) );
1426 : : }
1427 : 0 : return sal_False;
1428 : : }
1429 : :
1430 : 0 : void LingTest::CheckTags( TokenList &aReference, TokenList &aTestee, sal_Bool bFixTags )
1431 : : {
1432 : 0 : size_t i=0,j=0;
1433 : : // Clean old Warnings
1434 : 0 : aCompareWarningList.clear();
1435 : :
1436 : : /* in xml tags, do not require the following tags
1437 : : comment
1438 : : bookmark_value
1439 : : emph
1440 : : item
1441 : : br
1442 : : */
1443 : :
1444 : : // filter uninteresting Tags
1445 : 0 : TokenId aMetaTokens = 0;
1446 : 0 : for ( i=0 ; i < aReference.size() ; i++ )
1447 : : {
1448 : 0 : if ( !IsTagMandatory( aReference[ i ], aMetaTokens ) )
1449 : 0 : aReference[ i ].SetDone();
1450 : : }
1451 : :
1452 : 0 : aMetaTokens = 0;
1453 : 0 : for ( i=0 ; i < aTestee.size() ; i++ )
1454 : : {
1455 : 0 : if ( !IsTagMandatory( aTestee[ i ], aMetaTokens ) )
1456 : 0 : aTestee[ i ].SetDone();
1457 : : }
1458 : :
1459 : : // remove all matching tags
1460 : 0 : for ( i=0 ; i < aReference.size() ; i++ )
1461 : : {
1462 : 0 : if ( aReference[ i ].IsDone() )
1463 : 0 : continue;
1464 : :
1465 : 0 : sal_Bool bTagFound = sal_False;
1466 : 0 : for ( j=0 ; j < aTestee.size() && !bTagFound ; j++ )
1467 : : {
1468 : 0 : if ( aTestee[ j ].IsDone() )
1469 : 0 : continue;
1470 : :
1471 : 0 : if ( aReference[ i ].MatchesTranslation( aTestee[ j ], sal_False, aCompareWarningList ) )
1472 : : {
1473 : 0 : aReference[ i ].SetDone();
1474 : 0 : aTestee[ j ].SetDone();
1475 : 0 : bTagFound = sal_True;
1476 : : }
1477 : : }
1478 : : }
1479 : :
1480 : 0 : sal_Bool bCanFix = sal_True;
1481 : :
1482 : 0 : if ( bFixTags )
1483 : : {
1484 : : // we fix only if its a really simple case
1485 : 0 : sal_Int32 nTagCount = 0;
1486 : 0 : for ( i=0 ; i < aReference.size() ; i++ )
1487 : 0 : if ( !aReference[ i ].IsDone() )
1488 : 0 : nTagCount++;
1489 : 0 : if ( nTagCount > 1 )
1490 : 0 : bCanFix = sal_False;
1491 : :
1492 : 0 : nTagCount = 0;
1493 : 0 : for ( i=0 ; i < aTestee.size() ; i++ )
1494 : 0 : if ( !aTestee[ i ].IsDone() )
1495 : 0 : nTagCount++;
1496 : 0 : if ( nTagCount > 1 )
1497 : 0 : bCanFix = sal_False;
1498 : : }
1499 : :
1500 : : // generate errors for tags that have differing attributes
1501 : 0 : for ( i=0 ; i < aReference.size() ; i++ )
1502 : : {
1503 : 0 : if ( aReference[ i ].IsDone() )
1504 : 0 : continue;
1505 : :
1506 : 0 : sal_Bool bTagFound = sal_False;
1507 : 0 : for ( j=0 ; j < aTestee.size() && !bTagFound ; j++ )
1508 : : {
1509 : 0 : if ( aTestee[ j ].IsDone() )
1510 : 0 : continue;
1511 : :
1512 : 0 : if ( aReference[ i ].MatchesTranslation( aTestee[ j ], sal_True, aCompareWarningList, bCanFix && bFixTags ) )
1513 : : {
1514 : 0 : aReference[ i ].SetDone();
1515 : 0 : aTestee[ j ].SetDone();
1516 : 0 : bTagFound = sal_True;
1517 : : }
1518 : : }
1519 : : }
1520 : :
1521 : : // list remaining tags as errors
1522 : 0 : for ( i=0 ; i < aReference.size() ; i++ )
1523 : : {
1524 : 0 : if ( aReference[ i ].IsDone() )
1525 : 0 : continue;
1526 : :
1527 : 0 : aCompareWarningList.AddError( 20, "Missing Tag in Translation", aReference[ i ] );
1528 : : }
1529 : 0 : for ( i=0 ; i < aTestee.size() ; i++ )
1530 : : {
1531 : 0 : if ( aTestee[ i ].IsDone() )
1532 : 0 : continue;
1533 : :
1534 : 0 : aCompareWarningList.AddError( 21, "Extra Tag in Translation", aTestee[ i ] );
1535 : : }
1536 : :
1537 : 0 : for ( i=0 ; i < aReference.size() ; i++ )
1538 : 0 : aReference[ i ].SetDone( sal_False );
1539 : :
1540 : 0 : for ( i=0 ; i < aTestee.size() ; i++ )
1541 : 0 : aTestee[ i ].SetDone( sal_False );
1542 : 0 : }
1543 : :
1544 : 0 : void LingTest::CheckReference( GSILine *aReference )
1545 : : {
1546 : 0 : aReferenceParser.Parse( aReference->GetUText(), aReference->GetMessageList() );
1547 : 0 : }
1548 : :
1549 : 0 : void LingTest::CheckTestee( GSILine *aTestee, sal_Bool bHasSourceLine, sal_Bool bFixTags )
1550 : : {
1551 : 0 : aFixedTestee = aTestee->GetUText();
1552 : 0 : aTesteeParser.Parse( aFixedTestee, aTestee->GetMessageList() );
1553 : :
1554 : 0 : if ( bHasSourceLine )
1555 : 0 : CheckTags( aReferenceParser.GetTokenList(), aTesteeParser.GetTokenList(), bFixTags );
1556 : :
1557 : 0 : if ( bFixTags )
1558 : : {
1559 : 0 : TokenList& aTesteeTokens = aTesteeParser.GetTokenList();
1560 : 0 : sal_Bool bFixesDone = sal_False;
1561 : : // count backwards to allow replacing from right to left
1562 : : int i;
1563 : 0 : for ( i = aTesteeTokens.size() ; i > 0 ; )
1564 : : {
1565 : 0 : if ( aTesteeTokens[ --i ].HasBeenFixed() )
1566 : : {
1567 : 0 : bFixesDone = sal_True;
1568 : 0 : aFixedTestee = aFixedTestee.replaceAt( aTesteeTokens[ i ].nPos, aTesteeTokens[ i ].aTokenString.getLength(), aTesteeTokens[ i ].MakeTag() );
1569 : : }
1570 : : }
1571 : 0 : if ( bFixesDone )
1572 : : {
1573 : 0 : aTestee->SetUText( aFixedTestee );
1574 : 0 : aTestee->SetFixed();
1575 : : }
1576 : : }
1577 : 0 : }
1578 : :
1579 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|