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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <ctype.h>
22 : #include <stdlib.h>
23 : #include <stdio.h>
24 : #include <limits.h>
25 : #include <rtl/ustrbuf.hxx>
26 : #include <vcl/svapp.hxx>
27 : #include <svtools/htmltokn.h>
28 : #include <comphelper/string.hxx>
29 : #include "css1kywd.hxx"
30 : #include "parcss1.hxx"
31 :
32 :
33 : // Loop-Check: Um Endlos-Schleifen zu vermeiden, wird in jeder
34 : // Schalife geprueft, ob ein Fortschritt in der Eingabe-Position
35 : // stattgefunden hat
36 : #define LOOP_CHECK
37 :
38 : #ifdef LOOP_CHECK
39 :
40 : #define LOOP_CHECK_DECL \
41 : xub_StrLen nOldInPos = STRING_MAXLEN;
42 : #define LOOP_CHECK_RESTART \
43 : nOldInPos = STRING_MAXLEN;
44 : #define LOOP_CHECK_CHECK( where ) \
45 : OSL_ENSURE( nOldInPos!=nInPos || cNextCh==(sal_Unicode)EOF, where ); \
46 : if( nOldInPos==nInPos && cNextCh!=(sal_Unicode)EOF ) \
47 : break; \
48 : else \
49 : nOldInPos = nInPos;
50 :
51 : #else
52 :
53 : #define LOOP_CHECK_DECL
54 : #define LOOP_CHECK_RESTART
55 : #define LOOP_CHECK_CHECK( where )
56 :
57 : #endif
58 :
59 :
60 : const sal_Int32 MAX_LEN = 1024;
61 :
62 :
63 0 : void CSS1Parser::InitRead( const String& rIn )
64 : {
65 0 : nlLineNr = 0;
66 0 : nlLinePos = 0;
67 :
68 0 : bWhiteSpace = sal_True; // Wenn noch nichts gelesen wurde ist das wie WS
69 0 : bEOF = sal_False;
70 0 : eState = CSS1_PAR_WORKING;
71 0 : nValue = 0.;
72 :
73 0 : aIn = rIn;
74 0 : nInPos = 0;
75 0 : cNextCh = GetNextChar();
76 0 : nToken = GetNextToken();
77 0 : }
78 :
79 0 : sal_Unicode CSS1Parser::GetNextChar()
80 : {
81 0 : if( nInPos >= aIn.Len() )
82 : {
83 0 : bEOF = sal_True;
84 0 : return (sal_Unicode)EOF;
85 : }
86 :
87 0 : sal_Unicode c = aIn.GetChar( nInPos );
88 0 : nInPos++;
89 :
90 0 : if( c == '\n' )
91 : {
92 0 : IncLineNr();
93 0 : SetLinePos( 1L );
94 : }
95 : else
96 0 : IncLinePos();
97 :
98 0 : return c;
99 : }
100 :
101 : // Diese Funktion realisiert den in
102 : //
103 : // http://www.w3.orh/pub/WWW/TR/WD-css1.html
104 : // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
105 : //
106 : // beschriebenen Scanner fuer CSS1. Es handelt sich um eine direkte
107 : // Umsetzung der dort beschriebenen Lex-Grammatik
108 : //
109 0 : CSS1Token CSS1Parser::GetNextToken()
110 : {
111 0 : CSS1Token nRet = CSS1_NULL;
112 0 : aToken.Erase();
113 :
114 0 : do {
115 : // Merken, ob davor White-Space gelesen wurde
116 0 : sal_Bool bPrevWhiteSpace = bWhiteSpace;
117 0 : bWhiteSpace = sal_False;
118 :
119 0 : sal_Bool bNextCh = sal_True;
120 0 : switch( cNextCh )
121 : {
122 : case '/': // COMMENT | '/'
123 : {
124 0 : cNextCh = GetNextChar();
125 0 : if( '*' == cNextCh )
126 : {
127 : // COMMENT
128 0 : cNextCh = GetNextChar();
129 :
130 0 : sal_Bool bAsterix = sal_False;
131 0 : while( !(bAsterix && '/'==cNextCh) && !IsEOF() )
132 : {
133 0 : bAsterix = ('*'==cNextCh);
134 0 : cNextCh = GetNextChar();
135 : }
136 : }
137 : else
138 : {
139 : // '/'
140 0 : bNextCh = sal_False;
141 0 : nRet = CSS1_SLASH;
142 : }
143 : }
144 0 : break;
145 :
146 : case '@': // '@import' | '@XXX'
147 : {
148 0 : cNextCh = GetNextChar();
149 0 : if (comphelper::string::isalphaAscii(cNextCh))
150 : {
151 : // den naechsten Identifer scannen
152 0 : OUStringBuffer sTmpBuffer( 32L );
153 0 : do {
154 0 : sTmpBuffer.append( cNextCh );
155 0 : cNextCh = GetNextChar();
156 0 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
157 0 : '-' == cNextCh) && !IsEOF() );
158 :
159 0 : aToken += String(sTmpBuffer.makeStringAndClear());
160 :
161 : // und schauen, ob wir ihn kennen
162 0 : switch( aToken.GetChar(0) )
163 : {
164 : case 'i':
165 : case 'I':
166 0 : if( aToken.EqualsIgnoreCaseAscii(sCSS1_import) )
167 0 : nRet = CSS1_IMPORT_SYM;
168 0 : break;
169 : // /Feature: PrintExt
170 : case 'p':
171 : case 'P':
172 0 : if( aToken.EqualsIgnoreCaseAscii(sCSS1_page) )
173 0 : nRet = CSS1_PAGE_SYM;
174 0 : break;
175 : // /Feature: PrintExt
176 : }
177 :
178 : // Fehlerbehandlung: '@ident' und alles bis
179 : // zu einem Semikolon der dem Ende des folgenden
180 : // Blocks ignorieren
181 0 : if( CSS1_NULL==nRet )
182 : {
183 0 : aToken.Erase();
184 0 : sal_uInt16 nBlockLvl = 0;
185 0 : sal_Unicode cQuoteCh = 0;
186 0 : sal_Bool bDone = sal_False, bEscape = sal_False;
187 0 : while( !bDone && !IsEOF() )
188 : {
189 0 : sal_Bool bOldEscape = bEscape;
190 0 : bEscape = sal_False;
191 0 : switch( cNextCh )
192 : {
193 : case '{':
194 0 : if( !cQuoteCh && !bOldEscape )
195 0 : nBlockLvl++;
196 0 : break;
197 : case ';':
198 0 : if( !cQuoteCh && !bOldEscape )
199 0 : bDone = nBlockLvl==0;
200 0 : break;
201 : case '}':
202 0 : if( !cQuoteCh && !bOldEscape )
203 0 : bDone = --nBlockLvl==0;
204 0 : break;
205 : case '\"':
206 : case '\'':
207 0 : if( !bOldEscape )
208 : {
209 0 : if( cQuoteCh )
210 : {
211 0 : if( cQuoteCh == cNextCh )
212 0 : cQuoteCh = 0;
213 : }
214 : else
215 : {
216 0 : cQuoteCh = cNextCh;
217 : }
218 : }
219 0 : break;
220 : case '\\':
221 0 : if( !bOldEscape )
222 0 : bEscape = sal_True;
223 0 : break;
224 : }
225 0 : cNextCh = GetNextChar();
226 : }
227 : }
228 :
229 0 : bNextCh = sal_False;
230 : }
231 : }
232 0 : break;
233 :
234 : case '!': // '!' 'legal' | '!' 'important' | syntax error
235 : {
236 : // White Space ueberlesen
237 0 : cNextCh = GetNextChar();
238 0 : while( ( ' ' == cNextCh ||
239 0 : (cNextCh >= 0x09 && cNextCh <= 0x0d) ) && !IsEOF() )
240 : {
241 0 : bWhiteSpace = sal_True;
242 0 : cNextCh = GetNextChar();
243 : }
244 :
245 0 : if( 'i'==cNextCh || 'I'==cNextCh)
246 : {
247 : // den naechsten Identifer scannen
248 0 : OUStringBuffer sTmpBuffer( 32L );
249 0 : do {
250 0 : sTmpBuffer.append( cNextCh );
251 0 : cNextCh = GetNextChar();
252 0 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
253 0 : '-' == cNextCh) && !IsEOF() );
254 :
255 0 : aToken += String(sTmpBuffer.makeStringAndClear());
256 :
257 0 : if( ('i'==aToken.GetChar(0) || 'I'==aToken.GetChar(0)) &&
258 0 : aToken.EqualsIgnoreCaseAscii(sCSS1_important) )
259 : {
260 : // '!' 'important'
261 0 : nRet = CSS1_IMPORTANT_SYM;
262 : }
263 : else
264 : {
265 : // Fehlerbehandlung: '!' ignorieren, IDENT nicht
266 0 : nRet = CSS1_IDENT;
267 : }
268 :
269 0 : bWhiteSpace = sal_False;
270 0 : bNextCh = sal_False;
271 : }
272 : else
273 : {
274 : // Fehlerbehandlung: '!' ignorieren
275 0 : bNextCh = sal_False;
276 : }
277 : }
278 0 : break;
279 :
280 : case '\"':
281 : case '\'': // STRING
282 : {
283 : // \... geht noch nicht!!!
284 0 : sal_Unicode cQuoteChar = cNextCh;
285 0 : cNextCh = GetNextChar();
286 :
287 0 : OUStringBuffer sTmpBuffer( MAX_LEN );
288 0 : do {
289 0 : sTmpBuffer.append( cNextCh );
290 0 : cNextCh = GetNextChar();
291 0 : } while( cQuoteChar != cNextCh && !IsEOF() );
292 :
293 0 : aToken += String(sTmpBuffer.makeStringAndClear());
294 :
295 0 : nRet = CSS1_STRING;
296 : }
297 0 : break;
298 :
299 : case '0':
300 : case '1':
301 : case '2':
302 : case '3':
303 : case '4':
304 : case '5':
305 : case '6':
306 : case '7':
307 : case '8':
308 : case '9': // NUMBER | PERCENTAGE | LENGTH
309 : {
310 : // die aktuelle Position retten
311 0 : xub_StrLen nInPosSave = nInPos;
312 0 : sal_Unicode cNextChSave = cNextCh;
313 0 : sal_uInt32 nlLineNrSave = nlLineNr;
314 0 : sal_uInt32 nlLinePosSave = nlLinePos;
315 0 : sal_Bool bEOFSave = bEOF;
316 :
317 : // erstmal versuchen eine Hex-Zahl zu scannen
318 0 : OUStringBuffer sTmpBuffer( 16 );
319 0 : do {
320 0 : sTmpBuffer.append( cNextCh );
321 0 : cNextCh = GetNextChar();
322 0 : } while( sTmpBuffer.getLength() < 7 &&
323 0 : ( ('0'<=cNextCh && '9'>=cNextCh) ||
324 0 : ('A'<=cNextCh && 'F'>=cNextCh) ||
325 0 : ('a'<=cNextCh && 'f'>=cNextCh) ) &&
326 0 : !IsEOF() );
327 :
328 0 : if( sTmpBuffer.getLength()==6 )
329 : {
330 : // wir haben eine hexadezimale Farbe gefunden
331 0 : aToken += String(sTmpBuffer.makeStringAndClear());
332 0 : nRet = CSS1_HEXCOLOR;
333 0 : bNextCh = sal_False;
334 :
335 0 : break;
336 : }
337 :
338 : // sonst versuchen wir es mit einer Zahl
339 0 : nInPos = nInPosSave;
340 0 : cNextCh = cNextChSave;
341 0 : nlLineNr = nlLineNrSave;
342 0 : nlLinePos = nlLinePosSave;
343 0 : bEOF = bEOFSave;
344 :
345 : // erstmal die Zahl scannen
346 0 : sTmpBuffer.setLength( 0L );
347 0 : do {
348 0 : sTmpBuffer.append( cNextCh );
349 0 : cNextCh = GetNextChar();
350 0 : } while( (('0'<=cNextCh && '9'>=cNextCh) || '.'==cNextCh) &&
351 0 : !IsEOF() );
352 :
353 0 : aToken += String(sTmpBuffer.makeStringAndClear());
354 0 : nValue = OUString(aToken).toDouble();
355 :
356 : // White Space ueberlesen
357 0 : while( ( ' ' == cNextCh ||
358 0 : (cNextCh >= 0x09 && cNextCh <= 0x0d) ) && !IsEOF() )
359 : {
360 0 : bWhiteSpace = sal_True;
361 0 : cNextCh = GetNextChar();
362 : }
363 :
364 : // und nun Schauen, ob es eine Einheit gibt
365 0 : switch( cNextCh )
366 : {
367 : case '%': // PERCENTAGE
368 0 : bWhiteSpace = sal_False;
369 0 : nRet = CSS1_PERCENTAGE;
370 0 : break;
371 :
372 : case 'c':
373 : case 'C': // LENGTH cm | LENGTH IDENT
374 : case 'e':
375 : case 'E': // LENGTH (em | ex) | LENGTH IDENT
376 : case 'i':
377 : case 'I': // LENGTH inch | LENGTH IDENT
378 : case 'p':
379 : case 'P': // LENGTH (pt | px | pc) | LENGTH IDENT
380 : case 'm':
381 : case 'M': // LENGTH mm | LENGTH IDENT
382 : {
383 : // die aktuelle Position retten
384 0 : xub_StrLen nInPosOld = nInPos;
385 0 : sal_Unicode cNextChOld = cNextCh;
386 0 : sal_uLong nlLineNrOld = nlLineNr;
387 0 : sal_uLong nlLinePosOld = nlLinePos;
388 0 : sal_Bool bEOFOld = bEOF;
389 :
390 : // den naechsten Identifer scannen
391 0 : String aIdent;
392 0 : OUStringBuffer sTmpBuffer2( 64L );
393 0 : do {
394 0 : sTmpBuffer2.append( cNextCh );
395 0 : cNextCh = GetNextChar();
396 0 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
397 0 : '-' == cNextCh) && !IsEOF() );
398 :
399 0 : aIdent += String(sTmpBuffer2.makeStringAndClear());
400 :
401 : // Ist es eine Einheit?
402 0 : const sal_Char *pCmp1 = 0, *pCmp2 = 0, *pCmp3 = 0;
403 0 : double nScale1 = 1., nScale2 = 1.;
404 0 : CSS1Token nToken1 = CSS1_LENGTH,
405 0 : nToken2 = CSS1_LENGTH,
406 0 : nToken3 = CSS1_LENGTH;
407 0 : switch( aIdent.GetChar(0) )
408 : {
409 : case 'c':
410 : case 'C':
411 0 : pCmp1 = sCSS1_UNIT_cm;
412 0 : nScale1 = (72.*20.)/2.54; // twip
413 0 : break;
414 : case 'e':
415 : case 'E':
416 0 : pCmp1 = sCSS1_UNIT_em;
417 0 : nToken1 = CSS1_EMS;
418 :
419 0 : pCmp2 = sCSS1_UNIT_ex;
420 0 : nToken2 = CSS1_EMX;
421 0 : break;
422 : case 'i':
423 : case 'I':
424 0 : pCmp1 = sCSS1_UNIT_inch;
425 0 : nScale1 = 72.*20.; // twip
426 0 : break;
427 : case 'm':
428 : case 'M':
429 0 : pCmp1 = sCSS1_UNIT_mm;
430 0 : nScale1 = (72.*20.)/25.4; // twip
431 0 : break;
432 : case 'p':
433 : case 'P':
434 0 : pCmp1 = sCSS1_UNIT_pt;
435 0 : nScale1 = 20.; // twip
436 :
437 0 : pCmp2 = sCSS1_UNIT_pc;
438 0 : nScale2 = 12.*20.; // twip
439 :
440 0 : pCmp3 = sCSS1_UNIT_px;
441 0 : nToken3 = CSS1_PIXLENGTH;
442 0 : break;
443 : }
444 :
445 0 : double nScale = 0.0;
446 : OSL_ENSURE( pCmp1, "Wo kommt das erste Zeichen her?" );
447 0 : if( aIdent.EqualsIgnoreCaseAscii(pCmp1) )
448 : {
449 0 : nScale = nScale1;
450 0 : nRet = nToken1;
451 : }
452 0 : else if( pCmp2 &&
453 0 : aIdent.EqualsIgnoreCaseAscii(pCmp2) )
454 : {
455 0 : nScale = nScale2;
456 0 : nRet = nToken2;
457 : }
458 0 : else if( pCmp3 &&
459 0 : aIdent.EqualsIgnoreCaseAscii(pCmp3) )
460 : {
461 0 : nScale = 1.; // nScale3
462 0 : nRet = nToken3;
463 : }
464 : else
465 : {
466 0 : nRet = CSS1_NUMBER;
467 : }
468 :
469 0 : if( CSS1_LENGTH==nRet && nScale!=1.0 )
470 0 : nValue *= nScale;
471 :
472 0 : if( nRet == CSS1_NUMBER )
473 : {
474 0 : nInPos = nInPosOld;
475 0 : cNextCh = cNextChOld;
476 0 : nlLineNr = nlLineNrOld;
477 0 : nlLinePos = nlLinePosOld;
478 0 : bEOF = bEOFOld;
479 : }
480 : else
481 : {
482 0 : bWhiteSpace = sal_False;
483 : }
484 0 : bNextCh = sal_False;
485 : }
486 0 : break;
487 : default: // NUMBER IDENT
488 0 : bNextCh = sal_False;
489 0 : nRet = CSS1_NUMBER;
490 0 : break;
491 0 : }
492 : }
493 0 : break;
494 :
495 : case ':': // ':'
496 : // link/visited/active abfangen !!!
497 0 : nRet = CSS1_COLON;
498 0 : break;
499 :
500 : case '.': // DOT_W_WS | DOT_WO_WS
501 0 : nRet = bPrevWhiteSpace ? CSS1_DOT_W_WS : CSS1_DOT_WO_WS;
502 0 : break;
503 :
504 : case '+': // '+'
505 0 : nRet = CSS1_PLUS;
506 0 : break;
507 :
508 : case '-': // '-'
509 0 : nRet = CSS1_MINUS;
510 0 : break;
511 :
512 : case '{': // '{'
513 0 : nRet = CSS1_OBRACE;
514 0 : break;
515 :
516 : case '}': // '}'
517 0 : nRet = CSS1_CBRACE;
518 0 : break;
519 :
520 : case ';': // ';'
521 0 : nRet = CSS1_SEMICOLON;
522 0 : break;
523 :
524 : case ',': // ','
525 0 : nRet = CSS1_COMMA;
526 0 : break;
527 :
528 : case '#': // '#'
529 0 : cNextCh = GetNextChar();
530 0 : if( ('0'<=cNextCh && '9'>=cNextCh) ||
531 0 : ('a'<=cNextCh && 'f'>=cNextCh) ||
532 0 : ('A'<=cNextCh && 'F'>=cNextCh) )
533 : {
534 : // die aktuelle Position retten
535 0 : xub_StrLen nInPosSave = nInPos;
536 0 : sal_Unicode cNextChSave = cNextCh;
537 0 : sal_uLong nlLineNrSave = nlLineNr;
538 0 : sal_uLong nlLinePosSave = nlLinePos;
539 0 : sal_Bool bEOFSave = bEOF;
540 :
541 : // erstmal versuchen eine Hex-Zahl zu scannen
542 0 : OUStringBuffer sTmpBuffer( 6L );
543 0 : do {
544 0 : sTmpBuffer.append( cNextCh );
545 0 : cNextCh = GetNextChar();
546 0 : } while( sTmpBuffer.getLength() < 7 &&
547 0 : ( ('0'<=cNextCh && '9'>=cNextCh) ||
548 0 : ('A'<=cNextCh && 'F'>=cNextCh) ||
549 0 : ('a'<=cNextCh && 'f'>=cNextCh) ) &&
550 0 : !IsEOF() );
551 :
552 0 : if( sTmpBuffer.getLength()==6 || sTmpBuffer.getLength()==3 )
553 : {
554 : // wir haben eine hexadezimale Farbe gefunden
555 0 : aToken += String(sTmpBuffer.makeStringAndClear());
556 0 : nRet = CSS1_HEXCOLOR;
557 0 : bNextCh = sal_False;
558 :
559 0 : break;
560 : }
561 :
562 : // sonst versuchen wir es mit einer Zahl
563 0 : nInPos = nInPosSave;
564 0 : cNextCh = cNextChSave;
565 0 : nlLineNr = nlLineNrSave;
566 0 : nlLinePos = nlLinePosSave;
567 0 : bEOF = bEOFSave;
568 : }
569 :
570 0 : nRet = CSS1_HASH;
571 0 : bNextCh = sal_False;
572 0 : break;
573 :
574 : case ' ':
575 : case '\t':
576 : case '\r':
577 : case '\n': // White-Space
578 0 : bWhiteSpace = sal_True;
579 0 : break;
580 :
581 : case (sal_Unicode)EOF:
582 0 : if( IsEOF() )
583 : {
584 0 : eState = CSS1_PAR_ACCEPTED;
585 0 : bNextCh = sal_False;
586 0 : break;
587 : }
588 : // kein break;
589 :
590 : default: // IDENT | syntax error
591 0 : if (comphelper::string::isalphaAscii(cNextCh))
592 : {
593 : // IDENT
594 :
595 0 : sal_Bool bHexColor = sal_True;
596 :
597 : // den naechsten Identifer scannen
598 0 : OUStringBuffer sTmpBuffer( 64L );
599 0 : do {
600 0 : sTmpBuffer.append( cNextCh );
601 0 : if( bHexColor )
602 : {
603 0 : bHexColor = sTmpBuffer.getLength()<7 &&
604 0 : ( ('0'<=cNextCh && '9'>=cNextCh) ||
605 0 : ('A'<=cNextCh && 'F'>=cNextCh) ||
606 0 : ('a'<=cNextCh && 'f'>=cNextCh) );
607 : }
608 0 : cNextCh = GetNextChar();
609 0 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
610 0 : '-' == cNextCh) && !IsEOF() );
611 :
612 0 : aToken += String(sTmpBuffer.makeStringAndClear());
613 :
614 0 : if( bHexColor && sTmpBuffer.getLength()==6 )
615 : {
616 0 : bNextCh = sal_False;
617 0 : nRet = CSS1_HEXCOLOR;
618 :
619 0 : break;
620 : }
621 0 : if( '('==cNextCh &&
622 0 : ( (('u'==aToken.GetChar(0) || 'U'==aToken.GetChar(0)) &&
623 0 : aToken.EqualsIgnoreCaseAscii(sCSS1_url)) ||
624 0 : (('r'==aToken.GetChar(0) || 'R'==aToken.GetChar(0)) &&
625 0 : aToken.EqualsIgnoreCaseAscii(sCSS1_rgb)) ) )
626 : {
627 0 : sal_uInt16 nNestCnt = 0;
628 0 : OUStringBuffer sTmpBuffer2( 64L );
629 0 : do {
630 0 : sTmpBuffer2.append( cNextCh );
631 0 : switch( cNextCh )
632 : {
633 0 : case '(': nNestCnt++; break;
634 0 : case ')': nNestCnt--; break;
635 : }
636 0 : cNextCh = GetNextChar();
637 0 : } while( (nNestCnt>1 || ')'!=cNextCh) && !IsEOF() );
638 0 : sTmpBuffer2.append( cNextCh );
639 0 : aToken += String(sTmpBuffer2.makeStringAndClear());
640 0 : bNextCh = sal_True;
641 0 : nRet = 'u'==aToken.GetChar(0) || 'U'==aToken.GetChar(0)
642 : ? CSS1_URL
643 0 : : CSS1_RGB;
644 : }
645 : else
646 : {
647 0 : bNextCh = sal_False;
648 0 : nRet = CSS1_IDENT;
649 0 : }
650 : }
651 : // Fehlerbehandlung: Zeichen ignorieren
652 0 : break;
653 : }
654 0 : if( bNextCh )
655 0 : cNextCh = GetNextChar();
656 :
657 0 : } while( CSS1_NULL==nRet && IsParserWorking() );
658 :
659 0 : return nRet;
660 : }
661 :
662 :
663 : // Dies folegenden Funktionen realisieren den in
664 : //
665 : // http://www.w3.orh/pub/WWW/TR/WD-css1.html
666 : // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
667 : //
668 : // beschriebenen Parser fuer CSS1. Es handelt sich um eine direkte
669 : // Umsetzung der dort beschriebenen Grammatik
670 :
671 : // stylesheet
672 : // : import* rule*
673 : //
674 : // import
675 : // : IMPORT_SYM url
676 : //
677 : // url
678 : // : STRING
679 : //
680 0 : void CSS1Parser::ParseStyleSheet()
681 : {
682 0 : LOOP_CHECK_DECL
683 :
684 : // import*
685 0 : sal_Bool bDone = sal_False;
686 0 : while( !bDone && IsParserWorking() )
687 : {
688 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/import *" )
689 :
690 0 : switch( nToken )
691 : {
692 : case CSS1_IMPORT_SYM:
693 : // IMPORT_SYM url
694 : // url ueberspringen wir ungeprueft
695 0 : nToken = GetNextToken();
696 0 : break;
697 : case CSS1_IDENT: // Look-Aheads
698 : case CSS1_DOT_W_WS:
699 : case CSS1_HASH:
700 : // /Feature: PrintExt
701 : case CSS1_PAGE_SYM:
702 : // /Feature: PrintExt
703 : // rule
704 0 : bDone = sal_True;
705 0 : break;
706 : default:
707 : // Fehlerbehandlung: ueberlesen
708 0 : break;
709 : }
710 :
711 0 : if( !bDone )
712 0 : nToken = GetNextToken();
713 : }
714 :
715 0 : LOOP_CHECK_RESTART
716 :
717 : // rule *
718 0 : while( IsParserWorking() )
719 : {
720 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/rule *" )
721 :
722 0 : switch( nToken )
723 : {
724 : case CSS1_IDENT: // Look-Aheads
725 : case CSS1_DOT_W_WS:
726 : case CSS1_HASH:
727 : // /Feature: PrintExt
728 : case CSS1_PAGE_SYM:
729 : // /Feature: PrintExt
730 : // rule
731 0 : ParseRule();
732 0 : break;
733 : default:
734 : // Fehlerbehandlung: ueberlesen
735 0 : nToken = GetNextToken();
736 0 : break;
737 : }
738 : }
739 0 : }
740 :
741 : // rule
742 : // : selector [ ',' selector ]*
743 : // '{' declaration [ ';' declaration ]* '}'
744 : //
745 0 : void CSS1Parser::ParseRule()
746 : {
747 : // selector
748 0 : CSS1Selector *pSelector = ParseSelector();
749 0 : if( !pSelector )
750 0 : return;
751 :
752 : // Selektor verarbeiten
753 0 : if( SelectorParsed( pSelector, sal_True ) )
754 0 : delete pSelector;
755 :
756 0 : LOOP_CHECK_DECL
757 :
758 : // [ ',' selector ]*
759 0 : while( CSS1_COMMA==nToken && IsParserWorking() )
760 : {
761 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/selector *" )
762 :
763 : // ',' ueberelesen
764 0 : nToken = GetNextToken();
765 :
766 : // selector
767 0 : pSelector = ParseSelector();
768 0 : if( !pSelector )
769 0 : return;
770 :
771 : // Selektor verarbeiten
772 0 : if( SelectorParsed( pSelector, sal_False ) )
773 0 : delete pSelector;
774 : }
775 :
776 : // '{'
777 0 : if( CSS1_OBRACE != nToken )
778 0 : return;
779 0 : nToken = GetNextToken();
780 :
781 : // declaration
782 0 : String aProperty;
783 0 : CSS1Expression *pExpr = ParseDeclaration( aProperty );
784 0 : if( !pExpr )
785 0 : return;
786 :
787 : // expression verarbeiten
788 0 : if( DeclarationParsed( aProperty, pExpr ) )
789 0 : delete pExpr;
790 :
791 0 : LOOP_CHECK_RESTART
792 :
793 : // [ ';' declaration ]*
794 0 : while( CSS1_SEMICOLON==nToken && IsParserWorking() )
795 : {
796 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/declaration *" )
797 :
798 : // ';'
799 0 : nToken = GetNextToken();
800 :
801 : // declaration
802 0 : if( CSS1_IDENT == nToken )
803 : {
804 0 : CSS1Expression *pExp = ParseDeclaration( aProperty );
805 0 : if( pExp )
806 : {
807 : // expression verarbeiten
808 0 : if( DeclarationParsed( aProperty, pExp ) )
809 0 : delete pExp;
810 : }
811 : }
812 : }
813 :
814 : // '}'
815 0 : if( CSS1_CBRACE == nToken )
816 0 : nToken = GetNextToken();
817 : }
818 :
819 : // selector
820 : // : simple_selector+ [ ':' pseudo_element ]?
821 : //
822 : // simple_selector
823 : // : element_name [ DOT_WO_WS class ]?
824 : // | DOT_W_WS class
825 : // | id_selector
826 : //
827 : // element_name
828 : // : IDENT
829 : //
830 : // class
831 : // : IDENT
832 : //
833 : // id_selector
834 : // : '#' IDENT
835 : //
836 : // pseude_element
837 : // : IDENT
838 : //
839 0 : CSS1Selector *CSS1Parser::ParseSelector()
840 : {
841 0 : CSS1Selector *pRoot = 0, *pLast = 0;
842 :
843 0 : sal_Bool bDone = sal_False;
844 0 : CSS1Selector *pNew = 0;
845 :
846 0 : LOOP_CHECK_DECL
847 :
848 : // simple_selector+
849 0 : while( !bDone && IsParserWorking() )
850 : {
851 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseSelector()" )
852 :
853 0 : sal_Bool bNextToken = sal_True;
854 :
855 0 : switch( nToken )
856 : {
857 : case CSS1_IDENT:
858 : {
859 : // element_name [ DOT_WO_WS class ]?
860 :
861 : // element_name
862 0 : String aElement = aToken;
863 0 : CSS1SelectorType eType = CSS1_SELTYPE_ELEMENT;
864 0 : nToken = GetNextToken();
865 :
866 0 : if( CSS1_DOT_WO_WS == nToken )
867 : {
868 : // DOT_WO_WS
869 0 : nToken = GetNextToken();
870 :
871 : // class
872 0 : if( CSS1_IDENT == nToken )
873 : {
874 0 : (aElement += '.') += aToken;
875 0 : eType = CSS1_SELTYPE_ELEM_CLASS;
876 : }
877 : else
878 : {
879 : // class fehlt
880 0 : return pRoot;
881 : }
882 : }
883 : else
884 : {
885 : // das war jetzt ein Look-Ahead
886 0 : bNextToken = sal_False;
887 : }
888 0 : pNew = new CSS1Selector( eType, aElement );
889 : }
890 0 : break;
891 : case CSS1_DOT_W_WS:
892 : // DOT_W_WS class
893 :
894 : // DOT_W_WS
895 0 : nToken = GetNextToken();
896 :
897 0 : if( CSS1_IDENT==nToken )
898 : {
899 : // class
900 0 : pNew = new CSS1Selector( CSS1_SELTYPE_CLASS, aToken );
901 : }
902 : else
903 : {
904 : // class fehlt
905 0 : return pRoot;
906 : }
907 0 : break;
908 : case CSS1_HASH:
909 : // '#' id_selector
910 :
911 : // '#'
912 0 : nToken = GetNextToken();
913 :
914 0 : if( CSS1_IDENT==nToken )
915 : {
916 : // id_selector
917 0 : pNew = new CSS1Selector( CSS1_SELTYPE_ID, aToken );
918 : }
919 : else
920 : {
921 : // id_selector fehlt
922 0 : return pRoot;
923 : }
924 0 : break;
925 :
926 : // /Feature: PrintExt
927 : case CSS1_PAGE_SYM:
928 : {
929 : // @page
930 0 : pNew = new CSS1Selector( CSS1_SELTYPE_PAGE, aToken );
931 : }
932 0 : break;
933 : // /Feature: PrintExt
934 :
935 : default:
936 : // wir wissen nicht was kommt, also aufhoehren
937 0 : bDone = sal_True;
938 0 : break;
939 : }
940 :
941 : // falls ein Selektor angelegt wurd, ihn speichern
942 0 : if( pNew )
943 : {
944 : OSL_ENSURE( (pRoot!=0) == (pLast!=0),
945 : "Root-Selektor, aber kein Last" );
946 0 : if( pLast )
947 0 : pLast->SetNext( pNew );
948 : else
949 0 : pRoot = pNew;
950 :
951 0 : pLast = pNew;
952 0 : pNew = 0;
953 : }
954 :
955 0 : if( bNextToken && !bDone )
956 0 : nToken = GetNextToken();
957 : }
958 :
959 0 : if( !pRoot )
960 : {
961 : // simple_selector fehlt
962 0 : return pRoot;
963 : }
964 :
965 : // [ ':' pseudo_element ]?
966 0 : if( CSS1_COLON==nToken && IsParserWorking() )
967 : {
968 : // ':' pseudo element
969 0 : nToken = GetNextToken();
970 0 : if( CSS1_IDENT==nToken )
971 : {
972 0 : pLast->SetNext( new CSS1Selector(CSS1_SELTYPE_PSEUDO,aToken) );
973 0 : nToken = GetNextToken();
974 : }
975 : else
976 : {
977 : // pseudo_element fehlt
978 0 : return pRoot;
979 : }
980 : }
981 :
982 0 : return pRoot;
983 : }
984 :
985 : // declaration
986 : // : property ':' expr prio?
987 : // | /* empty */
988 : //
989 : // expression
990 : // : term [ operator term ]*
991 : //
992 : // term
993 : // : unary_operator?
994 : // [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT |
995 : // HEXCOLOR | URL | RGB ]
996 : //
997 : // operator
998 : // : '/' | ',' | /* empty */
999 : //
1000 : // unary_operator
1001 : // : '-' | '+'
1002 : //
1003 : // property
1004 : // : ident
1005 : //
1006 : // das Vorzeichen wird nur fuer numerische Werte (ausser PERCENTAGE)
1007 : // beruecksichtigt und wird auf nValue angewendet!
1008 0 : CSS1Expression *CSS1Parser::ParseDeclaration( String& rProperty )
1009 : {
1010 0 : CSS1Expression *pRoot = 0, *pLast = 0;
1011 :
1012 : // property
1013 0 : if( CSS1_IDENT != nToken )
1014 : {
1015 : // property fehlt
1016 0 : return pRoot;
1017 : }
1018 0 : rProperty = aToken;
1019 :
1020 0 : nToken = GetNextToken();
1021 :
1022 :
1023 : // ':'
1024 0 : if( CSS1_COLON != nToken )
1025 : {
1026 : // ':' fehlt
1027 0 : return pRoot;
1028 : }
1029 0 : nToken = GetNextToken();
1030 :
1031 : // term [operator term]*
1032 : // hier sind wir sehr lax, was die Syntax angeht, sollte aber kein
1033 : // Problem sein
1034 0 : sal_Bool bDone = sal_False;
1035 0 : sal_Unicode cSign = 0, cOp = 0;
1036 0 : CSS1Expression *pNew = 0;
1037 :
1038 0 : LOOP_CHECK_DECL
1039 :
1040 0 : while( !bDone && IsParserWorking() )
1041 : {
1042 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseDeclaration()" )
1043 :
1044 0 : switch( nToken )
1045 : {
1046 : case CSS1_MINUS:
1047 0 : cSign = '-';
1048 0 : break;
1049 :
1050 : case CSS1_PLUS:
1051 0 : cSign = '+';
1052 0 : break;
1053 :
1054 : case CSS1_NUMBER:
1055 : case CSS1_LENGTH:
1056 : case CSS1_PIXLENGTH:
1057 : case CSS1_EMS:
1058 : case CSS1_EMX:
1059 0 : if( '-'==cSign )
1060 0 : nValue = -nValue;
1061 : case CSS1_STRING:
1062 : case CSS1_PERCENTAGE:
1063 : case CSS1_IDENT:
1064 : case CSS1_URL:
1065 : case CSS1_RGB:
1066 : case CSS1_HEXCOLOR:
1067 0 : pNew = new CSS1Expression( nToken, aToken, nValue, cOp );
1068 0 : nValue = 0; // sonst landet das auch im naechsten Ident
1069 0 : cSign = 0;
1070 0 : cOp = 0;
1071 0 : break;
1072 :
1073 : case CSS1_SLASH:
1074 0 : cOp = '/';
1075 0 : cSign = 0;
1076 0 : break;
1077 :
1078 : case CSS1_COMMA:
1079 0 : cOp = ',';
1080 0 : cSign = 0;
1081 0 : break;
1082 :
1083 : default:
1084 0 : bDone = sal_True;
1085 0 : break;
1086 : }
1087 :
1088 : // falls ein Expression angelegt wurde, diesen speichern
1089 0 : if( pNew )
1090 : {
1091 : OSL_ENSURE( (pRoot!=0) == (pLast!=0),
1092 : "Root-Selektor, aber kein Last" );
1093 0 : if( pLast )
1094 0 : pLast->SetNext( pNew );
1095 : else
1096 0 : pRoot = pNew;
1097 :
1098 0 : pLast = pNew;
1099 0 : pNew = 0;
1100 : }
1101 :
1102 0 : if( !bDone )
1103 0 : nToken = GetNextToken();
1104 : }
1105 :
1106 0 : if( !pRoot )
1107 : {
1108 : // term fehlt
1109 0 : return pRoot;
1110 : }
1111 :
1112 : // prio?
1113 0 : if( CSS1_IMPORTANT_SYM==nToken )
1114 : {
1115 : // IMPORTANT_SYM
1116 0 : nToken = GetNextToken();
1117 : }
1118 :
1119 0 : return pRoot;
1120 : }
1121 :
1122 :
1123 1 : CSS1Parser::CSS1Parser()
1124 : : nValue(0)
1125 : , eState(CSS1_PAR_ACCEPTED)
1126 1 : , nToken(CSS1_NULL)
1127 : {
1128 1 : }
1129 :
1130 1 : CSS1Parser::~CSS1Parser()
1131 : {
1132 1 : }
1133 :
1134 :
1135 0 : sal_Bool CSS1Parser::ParseStyleSheet( const String& rIn )
1136 : {
1137 0 : String aTmp( rIn );
1138 :
1139 : sal_Unicode c;
1140 0 : while( aTmp.Len() &&
1141 0 : ( ' '==(c=aTmp.GetChar(0)) || '\t'==c || '\r'==c || '\n'==c ) )
1142 0 : aTmp.Erase( 0, 1 );
1143 :
1144 0 : while( aTmp.Len() && ( ' '==(c=aTmp.GetChar( aTmp.Len()-1))
1145 0 : || '\t'==c || '\r'==c || '\n'==c ) )
1146 0 : aTmp.Erase( aTmp.Len()-1 );
1147 :
1148 : // SGML-Kommentare entfernen
1149 0 : if( aTmp.Len() >= 4 &&
1150 0 : aTmp.CompareToAscii("<!--",4) == COMPARE_EQUAL )
1151 0 : aTmp.Erase( 0, 4 );
1152 :
1153 0 : if( aTmp.Len() >=3 &&
1154 0 : aTmp.Copy(aTmp.Len()-3).CompareToAscii("-->") == COMPARE_EQUAL )
1155 0 : aTmp.Erase( aTmp.Len()-3 );
1156 :
1157 0 : if( !aTmp.Len() )
1158 0 : return sal_True;
1159 :
1160 0 : InitRead( aTmp );
1161 :
1162 0 : ParseStyleSheet();
1163 :
1164 0 : return sal_True;
1165 : }
1166 :
1167 :
1168 0 : sal_Bool CSS1Parser::ParseStyleOption( const String& rIn )
1169 : {
1170 0 : if( !rIn.Len() )
1171 0 : return sal_True;
1172 :
1173 0 : InitRead( rIn );
1174 :
1175 : // fdo#41796: skip over spurious semicolons
1176 0 : while (CSS1_SEMICOLON == nToken)
1177 : {
1178 0 : nToken = GetNextToken();
1179 : }
1180 :
1181 0 : String aProperty;
1182 0 : CSS1Expression *pExpr = ParseDeclaration( aProperty );
1183 0 : if( !pExpr )
1184 : {
1185 0 : return sal_False;
1186 : }
1187 :
1188 : // expression verarbeiten
1189 0 : if( DeclarationParsed( aProperty, pExpr ) )
1190 0 : delete pExpr;
1191 :
1192 0 : LOOP_CHECK_DECL
1193 :
1194 : // [ ';' declaration ]*
1195 0 : while( CSS1_SEMICOLON==nToken && IsParserWorking() )
1196 : {
1197 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleOption()" )
1198 :
1199 0 : nToken = GetNextToken();
1200 0 : if( CSS1_IDENT==nToken )
1201 : {
1202 0 : CSS1Expression *pExp = ParseDeclaration( aProperty );
1203 0 : if( pExp )
1204 : {
1205 : // expression verarbeiten
1206 0 : if( DeclarationParsed( aProperty, pExp ) )
1207 0 : delete pExp;
1208 : }
1209 : }
1210 : }
1211 :
1212 0 : return sal_True;
1213 : }
1214 :
1215 0 : bool CSS1Parser::SelectorParsed( CSS1Selector* /* pSelector */, bool /*bFirst*/ )
1216 : {
1217 : // Selektor loeschen
1218 0 : return true;
1219 : }
1220 :
1221 0 : sal_Bool CSS1Parser::DeclarationParsed( const String& /*rProperty*/,
1222 : const CSS1Expression * /* pExpr */ )
1223 : {
1224 : // Deklaration loeschen
1225 0 : return sal_True;
1226 : }
1227 :
1228 :
1229 0 : CSS1Selector::~CSS1Selector()
1230 : {
1231 0 : delete pNext;
1232 0 : }
1233 :
1234 0 : CSS1Expression::~CSS1Expression()
1235 : {
1236 0 : delete pNext;
1237 0 : }
1238 :
1239 0 : sal_Bool CSS1Expression::GetURL( String& rURL ) const
1240 : {
1241 : OSL_ENSURE( CSS1_URL==eType, "CSS1-Ausruck ist keine Farbe URL" );
1242 :
1243 : OSL_ENSURE( aValue.CompareIgnoreCaseToAscii( sCSS1_url, 3 ) ==
1244 : COMPARE_EQUAL &&
1245 : aValue.Len() > 5 &&
1246 : '(' == aValue.GetChar(3) &&
1247 : ')' == aValue.GetChar(aValue.Len()-1),
1248 : "keine gueltiges URL(...)" );
1249 :
1250 0 : sal_Bool bRet = sal_False;
1251 :
1252 0 : if( aValue.Len() > 5 )
1253 : {
1254 0 : rURL = aValue.Copy( 4, aValue.Len()-5 );
1255 0 : rURL = comphelper::string::strip(rURL, ' ');
1256 0 : bRet = sal_True;
1257 : }
1258 :
1259 0 : return bRet;
1260 : }
1261 :
1262 0 : sal_Bool CSS1Expression::GetColor( Color &rColor ) const
1263 : {
1264 : OSL_ENSURE( CSS1_IDENT==eType || CSS1_RGB==eType ||
1265 : CSS1_HEXCOLOR==eType || CSS1_STRING==eType,
1266 : "CSS1-Ausruck kann keine Farbe sein" );
1267 :
1268 0 : sal_Bool bRet = sal_False;
1269 0 : sal_uInt32 nColor = SAL_MAX_UINT32;
1270 :
1271 0 : switch( eType )
1272 : {
1273 : case CSS1_RGB:
1274 : {
1275 0 : sal_uInt8 aColors[3] = { 0, 0, 0 };
1276 :
1277 : OSL_ENSURE( aValue.CompareIgnoreCaseToAscii( sCSS1_rgb, 3 )
1278 : == COMPARE_EQUAL &&
1279 : aValue.Len() > 5 &&
1280 : '(' == aValue.GetChar( 3 ) &&
1281 : ')' == aValue.GetChar( aValue.Len()-1),
1282 : "keine gueltiges RGB(...)" );
1283 :
1284 0 : String aColorStr( aValue.Copy( 4, aValue.Len()-1 ) );
1285 :
1286 0 : xub_StrLen nPos = 0;
1287 0 : sal_uInt16 nCol = 0;
1288 :
1289 0 : while( nCol < 3 && nPos < aColorStr.Len() )
1290 : {
1291 : sal_Unicode c;
1292 0 : while( nPos < aColorStr.Len() &&
1293 0 : ((c=aColorStr.GetChar(nPos)) == ' ' || c == '\t' ||
1294 0 : c == '\n' || c== '\r' ) )
1295 0 : nPos++;
1296 :
1297 0 : xub_StrLen nEnd = aColorStr.Search( ',', nPos );
1298 0 : String aNumber;
1299 0 : if( STRING_NOTFOUND==nEnd )
1300 : {
1301 0 : aNumber = aColorStr.Copy(nPos);
1302 0 : nPos = aColorStr.Len();
1303 : }
1304 : else
1305 : {
1306 0 : aNumber = aColorStr.Copy( nPos, nEnd-nPos );
1307 0 : nPos = nEnd+1;
1308 : }
1309 :
1310 0 : sal_uInt16 nNumber = (sal_uInt16)aNumber.ToInt32();
1311 0 : if( aNumber.Search('%') != STRING_NOTFOUND )
1312 : {
1313 0 : if( nNumber > 100 )
1314 0 : nNumber = 100;
1315 0 : nNumber *= 255;
1316 0 : nNumber /= 100;
1317 : }
1318 0 : else if( nNumber > 255 )
1319 0 : nNumber = 255;
1320 :
1321 0 : aColors[nCol] = (sal_uInt8)nNumber;
1322 0 : nCol ++;
1323 0 : }
1324 :
1325 0 : rColor.SetRed( aColors[0] );
1326 0 : rColor.SetGreen( aColors[1] );
1327 0 : rColor.SetBlue( aColors[2] );
1328 :
1329 0 : bRet = sal_True; // etwas anderes als eine Farbe kann es nicht sein
1330 : }
1331 0 : break;
1332 :
1333 : case CSS1_IDENT:
1334 : case CSS1_STRING:
1335 : {
1336 0 : String aTmp( aValue );
1337 0 : aTmp.ToUpperAscii();
1338 0 : nColor = GetHTMLColor( aTmp );
1339 0 : bRet = nColor != SAL_MAX_UINT32;
1340 : }
1341 0 : if( bRet || CSS1_STRING != eType || !aValue.Len() ||
1342 0 : aValue.GetChar( 0 )!='#' )
1343 0 : break;
1344 :
1345 : case CSS1_HEXCOLOR:
1346 : {
1347 : // HACK fuer MS-IE: DIe Farbe kann auch in einem String stehen
1348 0 : xub_StrLen nOffset = CSS1_STRING==eType ? 1 : 0;
1349 0 : sal_Bool bDouble = aValue.Len()-nOffset == 3;
1350 0 : xub_StrLen i = nOffset, nEnd = (bDouble ? 3 : 6) + nOffset;
1351 :
1352 0 : nColor = 0;
1353 0 : for( ; i<nEnd; i++ )
1354 : {
1355 0 : sal_Unicode c = (i<aValue.Len() ? aValue.GetChar(i)
1356 0 : : '0' );
1357 0 : if( c >= '0' && c <= '9' )
1358 0 : c -= 48;
1359 0 : else if( c >= 'A' && c <= 'F' )
1360 0 : c -= 55;
1361 0 : else if( c >= 'a' && c <= 'f' )
1362 0 : c -= 87;
1363 : else
1364 0 : c = 16;
1365 :
1366 0 : nColor *= 16;
1367 0 : if( c<16 )
1368 0 : nColor += c;
1369 0 : if( bDouble )
1370 : {
1371 0 : nColor *= 16;
1372 0 : if( c<16 )
1373 0 : nColor += c;
1374 : }
1375 : }
1376 0 : bRet = sal_True;
1377 : }
1378 0 : break;
1379 : default:
1380 : ;
1381 : }
1382 :
1383 :
1384 0 : if( bRet && nColor!=SAL_MAX_UINT32 )
1385 : {
1386 0 : rColor.SetRed( (sal_uInt8)((nColor & 0x00ff0000UL) >> 16) );
1387 0 : rColor.SetGreen( (sal_uInt8)((nColor & 0x0000ff00UL) >> 8) );
1388 0 : rColor.SetBlue( (sal_uInt8)(nColor & 0x000000ffUL) );
1389 : }
1390 :
1391 0 : return bRet;
1392 99 : }
1393 :
1394 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|