~vaifrax/inkscape/bugfix170049

« back to all changes in this revision

Viewing changes to src/dom/svgparser.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Phoebe DOM Implementation.
 
3
 *
 
4
 * This is a C++ approximation of the W3C DOM model, which follows
 
5
 * fairly closely the specifications in the various .idl files, copies of
 
6
 * which are provided for reference.  Most important is this one:
 
7
 *
 
8
 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html
 
9
 *
 
10
 * Authors:
 
11
 *   Bob Jamison
 
12
 *
 
13
 * Copyright (C) 2005 Bob Jamison
 
14
 *
 
15
 *  This library is free software; you can redistribute it and/or
 
16
 *  modify it under the terms of the GNU Lesser General Public
 
17
 *  License as published by the Free Software Foundation; either
 
18
 *  version 2.1 of the License, or (at your option) any later version.
 
19
 *
 
20
 *  This library is distributed in the hope that it will be useful,
 
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
23
 *  Lesser General Public License for more details.
 
24
 *
 
25
 *  You should have received a copy of the GNU Lesser General Public
 
26
 *  License along with this library; if not, write to the Free Software
 
27
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
28
 */
 
29
 
 
30
 
 
31
#include "svgparser.h"
 
32
#include "cssparser.h"
 
33
#include "charclass.h"
 
34
 
 
35
#include <stdarg.h>
 
36
 
 
37
#define SVG_NAMESPACE "http://www.w3.org/2000/svg"
 
38
 
 
39
namespace org
 
40
{
 
41
namespace w3c
 
42
{
 
43
namespace dom
 
44
{
 
45
namespace svg
 
46
{
 
47
 
 
48
 
 
49
//#########################################################################
 
50
//# M E S S A G E S
 
51
//#########################################################################
 
52
 
 
53
 
 
54
/**
 
55
 *
 
56
 */
 
57
void SvgParser::error(char *fmt, ...)
 
58
{
 
59
    va_list args;
 
60
    fprintf(stderr, "SvgParser:error:");
 
61
    va_start(args, fmt);
 
62
    vfprintf(stderr, fmt, args);
 
63
    va_end(args) ;
 
64
    fprintf(stderr, "\n");
 
65
}
 
66
 
 
67
 
 
68
 
 
69
//#########################################################################
 
70
//# P A R S I N G
 
71
//#########################################################################
 
72
 
 
73
/**
 
74
 *  Get the character at the position and record the fact
 
75
 */
 
76
XMLCh SvgParser::get(int p)
 
77
{
 
78
    if (p >= parselen)
 
79
        return 0;
 
80
    XMLCh ch = parsebuf[p];
 
81
    //printf("%c", ch);
 
82
    lastPosition = p;
 
83
    return ch;
 
84
}
 
85
 
 
86
 
 
87
 
 
88
/**
 
89
 *  Test if the given substring exists at the given position
 
90
 *  in parsebuf.  Use get() in case of out-of-bounds
 
91
 */
 
92
bool SvgParser::match(int pos, char *str)
 
93
{
 
94
    while (*str)
 
95
       {
 
96
       if (get(pos++) != *str++)
 
97
           return false;
 
98
       }
 
99
   return true;
 
100
}
 
101
 
 
102
/**
 
103
 *
 
104
 */
 
105
int SvgParser::skipwhite(int p)
 
106
{
 
107
  while (p < parselen)
 
108
    {
 
109
    //# XML COMMENT
 
110
    if (match(p, "<!--"))
 
111
        {
 
112
        p+=4;
 
113
        bool done=false;
 
114
        while (p<parselen)
 
115
            {
 
116
            if (match(p, "-->"))
 
117
                {
 
118
                p+=3;
 
119
                done=true;
 
120
                break;
 
121
                }
 
122
            p++;
 
123
            }
 
124
        lastPosition = p;
 
125
        if (!done)
 
126
            {
 
127
            error("unterminated <!-- .. --> comment");
 
128
            return -1;
 
129
            }
 
130
        }
 
131
    //# C comment
 
132
    else if (match(p, "/*"))
 
133
        {
 
134
        p+=2;
 
135
        bool done=false;
 
136
        while (p<parselen)
 
137
            {
 
138
            if (match(p, "*/"))
 
139
                {
 
140
                p+=2;
 
141
                done=true;
 
142
                break;
 
143
                }
 
144
            p++;
 
145
            }
 
146
        lastPosition = p;
 
147
        if (!done)
 
148
            {
 
149
            error("unterminated /* .. */ comment");
 
150
            return -1;
 
151
            }
 
152
        }
 
153
    else if (!isspace(get(p)))
 
154
        break;
 
155
    else
 
156
        p++;
 
157
    }
 
158
  lastPosition = p;
 
159
  return p;
 
160
}
 
161
 
 
162
/**
 
163
 * get a word from the buffer
 
164
 */
 
165
int SvgParser::getWord(int p, DOMString &result)
 
166
{
 
167
    XMLCh ch = get(p);
 
168
    if (!isLetter(ch))
 
169
        return p;
 
170
    DOMString str;
 
171
    str.push_back(ch);
 
172
    p++;
 
173
 
 
174
    while (p < parselen)
 
175
        {
 
176
        ch = get(p);
 
177
        if (isLetterOrDigit(ch) || ch=='-' || ch=='_')
 
178
            {
 
179
            str.push_back(ch);
 
180
            p++;
 
181
            }
 
182
        else if (ch == '\\')
 
183
            {
 
184
            p+=2;
 
185
            }
 
186
        else
 
187
            break;
 
188
        }
 
189
    result = str;
 
190
    return p;
 
191
}
 
192
 
 
193
 
 
194
# if 0
 
195
/**
 
196
 * get a word from the buffer
 
197
 */
 
198
int SvgParser::getNumber(int p0, double &result)
 
199
{
 
200
    int p=p0;
 
201
 
 
202
    DOMString str;
 
203
 
 
204
    //allow sign
 
205
    if (get(p) == '-')
 
206
        {
 
207
        p++;
 
208
        }
 
209
 
 
210
    while (p < parselen)
 
211
        {
 
212
        XMLCh ch = get(p);
 
213
        if (ch<'0' || ch>'9')
 
214
            break;
 
215
        str.push_back(ch);
 
216
        p++;
 
217
        }
 
218
    if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9')
 
219
        {
 
220
        p++;
 
221
        str.push_back('.');
 
222
        while (p < parselen)
 
223
            {
 
224
            XMLCh ch = get(p);
 
225
            if (ch<'0' || ch>'9')
 
226
                break;
 
227
            str.push_back(ch);
 
228
            p++;
 
229
            }
 
230
        }
 
231
    if (p>p0)
 
232
        {
 
233
        char *start = (char *)str.c_str();
 
234
        char *end   = NULL;
 
235
        double val = strtod(start, &end);
 
236
        if (end > start)
 
237
            {
 
238
            result = val;
 
239
            return p;
 
240
            }
 
241
        }
 
242
 
 
243
    //not a number
 
244
    return p0;
 
245
}
 
246
#endif
 
247
 
 
248
 
 
249
/**
 
250
 * get a word from the buffer
 
251
 */
 
252
int SvgParser::getNumber(int p0, double &result)
 
253
{
 
254
    int p=p0;
 
255
 
 
256
    char buf[64];
 
257
 
 
258
    int i;
 
259
    for (i=0 ; i<63 && p<parselen ; i++)
 
260
        {
 
261
        buf[i] = (char) get(p++);
 
262
        }
 
263
    buf[i] = '\0';
 
264
 
 
265
    char *start = buf;
 
266
    char *end   = NULL;
 
267
    double val = strtod(start, &end);
 
268
    if (end > start)
 
269
        {
 
270
        result = val;
 
271
        int count = (int)(end - start);
 
272
        p = p0 + count;
 
273
        return p;
 
274
        }
 
275
 
 
276
    //not a number
 
277
    return p0;
 
278
}
 
279
 
 
280
 
 
281
bool SvgParser::parseTransform(const DOMString &str)
 
282
{
 
283
    parsebuf = str;
 
284
    parselen = str.size();
 
285
 
 
286
    //printf("transform:%s\n", str.c_str());
 
287
 
 
288
    SVGTransformList transformList;
 
289
 
 
290
    int p = 0;
 
291
 
 
292
    while (p < parselen)
 
293
        {
 
294
        p = skipwhite(p);
 
295
        DOMString name;
 
296
        int p2 = getWord(p, name);
 
297
        if (p2<0)
 
298
            return false;
 
299
        if (p2<=p)
 
300
            {
 
301
            error("transform: need transform name");
 
302
            //return false;
 
303
            break;
 
304
            }
 
305
        p = p2;
 
306
        //printf("transform name:%s\n", name.c_str());
 
307
 
 
308
        //######### MATRIX
 
309
        if (name == "matrix")
 
310
            {
 
311
            p = skipwhite(p);
 
312
            if (get(p++) != '(')
 
313
                {
 
314
                error("matrix transform needs opening '('");
 
315
                return false;
 
316
                }
 
317
            int nrVals = 0;
 
318
            double vals[6];
 
319
            bool seenBrace = false;
 
320
            while (p < parselen && nrVals < 6)
 
321
                {
 
322
                p = skipwhite(p);
 
323
                double val;
 
324
                p2 = getNumber(p, val);
 
325
                if (p2<0)
 
326
                    return false;
 
327
                if (p2<=p)
 
328
                    {
 
329
                    error("matrix() expected number");
 
330
                    return false;
 
331
                    }
 
332
                vals[nrVals++] = val;
 
333
                p = skipwhite(p2);
 
334
                XMLCh ch = get(p);
 
335
                if (ch == ',')
 
336
                    {
 
337
                    p++;
 
338
                    p = skipwhite(p);
 
339
                    ch = get(p);
 
340
                    }
 
341
                if (ch == ')')
 
342
                    {
 
343
                    seenBrace = true;
 
344
                    p++;
 
345
                    break;
 
346
                    }
 
347
                }
 
348
            if (!seenBrace)
 
349
                {
 
350
                error("matrix() needs closing brace");
 
351
                return false;
 
352
                }
 
353
            if (nrVals != 6)
 
354
                {
 
355
                error("matrix() requires exactly 6 arguments");
 
356
                return false;
 
357
                }
 
358
            //We got our arguments
 
359
            //printf("translate: %f %f %f %f %f %f\n",
 
360
            //      vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
 
361
            SVGMatrix matrix(vals[0], vals[1], vals[2],
 
362
                             vals[3], vals[4], vals[5]);
 
363
            SVGTransform transform;
 
364
            transform.setMatrix(matrix);
 
365
            transformList.appendItem(transform);
 
366
            }
 
367
 
 
368
        //######### TRANSLATE
 
369
        else if (name == "translate")
 
370
            {
 
371
            p = skipwhite(p);
 
372
            if (get(p++) != '(')
 
373
                {
 
374
                error("matrix transform needs opening '('");
 
375
                return false;
 
376
                }
 
377
            p = skipwhite(p);
 
378
            double x;
 
379
            p2 = getNumber(p, x);
 
380
            if (p2<0)
 
381
                return false;
 
382
            if (p2<=p)
 
383
                {
 
384
                error("translate() expected 'x' value");
 
385
                return false;
 
386
                }
 
387
            p = skipwhite(p2);
 
388
            if (get(p) == ',')
 
389
                {
 
390
                p++;
 
391
                p = skipwhite(p);
 
392
                }
 
393
            double y;
 
394
            p2 = getNumber(p, y);
 
395
            if (p2<0)
 
396
                return false;
 
397
            if (p2<=p) //no y specified. use default
 
398
                y = 0.0;
 
399
            p = skipwhite(p2);
 
400
            if (get(p++) != ')')
 
401
                {
 
402
                error("translate() needs closing ')'");
 
403
                return false;
 
404
                }
 
405
            //printf("translate: %f %f\n", x, y);
 
406
            SVGTransform transform;
 
407
            transform.setTranslate(x, y);
 
408
            transformList.appendItem(transform);
 
409
            }
 
410
 
 
411
        //######### SCALE
 
412
        else if (name == "scale")
 
413
            {
 
414
            p = skipwhite(p);
 
415
            if (get(p++) != '(')
 
416
                {
 
417
                error("scale transform needs opening '('");
 
418
                return false;
 
419
                }
 
420
            p = skipwhite(p);
 
421
            double x;
 
422
            p2 = getNumber(p, x);
 
423
            if (p2<0)
 
424
                return false;
 
425
            if (p2<=p)
 
426
                {
 
427
                error("scale() expected 'x' value");
 
428
                return false;
 
429
                }
 
430
            p = skipwhite(p2);
 
431
            if (get(p) == ',')
 
432
                {
 
433
                p++;
 
434
                p = skipwhite(p);
 
435
                }
 
436
            double y;
 
437
            p2 = getNumber(p, y);
 
438
            if (p2<0)
 
439
                return false;
 
440
            if (p2<=p) //no y specified. use default
 
441
                y = x; // y is same as x.  uniform scaling
 
442
            p = skipwhite(p2);
 
443
            if (get(p++) != ')')
 
444
                {
 
445
                error("scale() needs closing ')'");
 
446
                return false;
 
447
                }
 
448
            //printf("scale: %f %f\n", x, y);
 
449
            SVGTransform transform;
 
450
            transform.setScale(x, y);
 
451
            transformList.appendItem(transform);
 
452
            }
 
453
 
 
454
        //######### ROTATE
 
455
        else if (name == "rotate")
 
456
            {
 
457
            p = skipwhite(p);
 
458
            if (get(p++) != '(')
 
459
                {
 
460
                error("rotate transform needs opening '('");
 
461
                return false;
 
462
                }
 
463
            p = skipwhite(p);
 
464
            double angle;
 
465
            p2 = getNumber(p, angle);
 
466
            if (p2<0)
 
467
                return false;
 
468
            if (p2<=p)
 
469
                {
 
470
                error("rotate() expected 'angle' value");
 
471
                return false;
 
472
                }
 
473
            p = skipwhite(p2);
 
474
            if (get(p) == ',')
 
475
                {
 
476
                p++;
 
477
                p = skipwhite(p);
 
478
                }
 
479
            double cx = 0.0;
 
480
            double cy = 0.0;
 
481
            p2 = getNumber(p, cx);
 
482
            if (p2>p)
 
483
                {
 
484
                p = skipwhite(p2);
 
485
                if (get(p) == ',')
 
486
                    {
 
487
                    p++;
 
488
                    p = skipwhite(p);
 
489
                    }
 
490
                p2 = getNumber(p, cy);
 
491
                if (p2<0)
 
492
                    return false;
 
493
                if (p2<=p)
 
494
                    {
 
495
                    error("rotate() arguments should be either rotate(angle) or rotate(angle, cx, cy)");
 
496
                    return false;
 
497
                    }
 
498
                p = skipwhite(p2);
 
499
                }
 
500
            if (get(p++) != ')')
 
501
                {
 
502
                error("rotate() needs closing ')'");
 
503
                return false;
 
504
                }
 
505
            //printf("rotate: %f %f %f\n", angle, cx, cy);
 
506
            SVGTransform transform;
 
507
            transform.setRotate(angle, cx, cy);
 
508
            transformList.appendItem(transform);
 
509
            }
 
510
 
 
511
        //######### SKEWX
 
512
        else if (name == "skewX")
 
513
            {
 
514
            p = skipwhite(p);
 
515
            if (get(p++) != '(')
 
516
                {
 
517
                error("skewX transform needs opening '('");
 
518
                return false;
 
519
                }
 
520
            p = skipwhite(p);
 
521
            double x;
 
522
            p2 = getNumber(p, x);
 
523
            if (p2<0)
 
524
                return false;
 
525
            if (p2<=p)
 
526
                {
 
527
                error("skewX() expected 'x' value");
 
528
                return false;
 
529
                }
 
530
            p = skipwhite(p2);
 
531
            if (get(p++) != ')')
 
532
                {
 
533
                error("skewX() needs closing ')'");
 
534
                return false;
 
535
                }
 
536
            //printf("skewX: %f\n", x);
 
537
            SVGTransform transform;
 
538
            transform.setSkewX(x);
 
539
            transformList.appendItem(transform);
 
540
            }
 
541
 
 
542
        //######### SKEWY
 
543
        else if (name == "skewY")
 
544
            {
 
545
            p = skipwhite(p);
 
546
            if (get(p++) != '(')
 
547
                {
 
548
                error("skewY transform needs opening '('");
 
549
                return false;
 
550
                }
 
551
            p = skipwhite(p);
 
552
            double y;
 
553
            p2 = getNumber(p, y);
 
554
            if (p2<0)
 
555
                return false;
 
556
            if (p2<=p)
 
557
                {
 
558
                error("skewY() expected 'y' value");
 
559
                return false;
 
560
                }
 
561
            p = skipwhite(p2);
 
562
            if (get(p++) != ')')
 
563
                {
 
564
                error("skewY() needs closing ')'");
 
565
                return false;
 
566
                }
 
567
            //printf("skewY: %f\n", y);
 
568
            SVGTransform transform;
 
569
            transform.setSkewY(y);
 
570
            transformList.appendItem(transform);
 
571
            }
 
572
 
 
573
        //### NONE OF THE ABOVE
 
574
        else
 
575
            {
 
576
            error("unknown transform type:'%s'", name.c_str());
 
577
            }
 
578
 
 
579
        p = skipwhite(p);
 
580
        XMLCh ch = get(p);
 
581
        if (ch == ',')
 
582
            {
 
583
            p++;
 
584
            p = skipwhite(p);
 
585
            }
 
586
 
 
587
        }//WHILE p<parselen
 
588
 
 
589
    return true;
 
590
}
 
591
 
 
592
 
 
593
/**
 
594
 *
 
595
 */
 
596
bool SvgParser::parseElement(ElementImpl *parent, ElementImpl *sourceElem)
 
597
{
 
598
    if (!parent || !sourceElem)
 
599
        {
 
600
        error("NULL source element");
 
601
        return false;
 
602
        }
 
603
 
 
604
    DOMString namespaceURI = sourceElem->getNamespaceURI();
 
605
    //printf("namespaceURI:%s\n", namespaceURI.c_str());
 
606
    DOMString tagName      = sourceElem->getTagName();
 
607
    printf("tag name:%s\n", tagName.c_str());
 
608
 
 
609
    ElementImpl *newElement = NULL;
 
610
    if (namespaceURI != SVG_NAMESPACE)
 
611
        {
 
612
        newElement = new SVGSVGElementImpl();
 
613
        newElement->assign(*sourceElem);
 
614
        parent->appendChild(newElement);
 
615
        }
 
616
    else //## SVG!!
 
617
        {
 
618
 
 
619
        //####################################################
 
620
        //## ATTRIBUTES
 
621
        //####################################################
 
622
        DOMString style = sourceElem->getAttribute("style");
 
623
        if (style.size() > 0)
 
624
            {
 
625
            css::CssParser parser;
 
626
            style.insert(0, "{");
 
627
            style.append("}");
 
628
            //printf("CSS:%s\n", style.c_str());
 
629
            if (!parser.parse(style))
 
630
                {
 
631
                error("parsing style attribute");
 
632
                }
 
633
            else
 
634
                {
 
635
                //printf("##parsed!\n");
 
636
                }
 
637
            }
 
638
 
 
639
        DOMString transform = sourceElem->getAttribute("transform");
 
640
        if (transform.size() > 0)
 
641
            {
 
642
            if (!parseTransform(transform))
 
643
                {
 
644
                error("parsing transform attribute");
 
645
                }
 
646
            else
 
647
                {
 
648
                //printf("##parsed!\n");
 
649
                }
 
650
            }
 
651
 
 
652
        //####################################################
 
653
        //## ELEMENT - SPECIFIC
 
654
        //####################################################
 
655
        if (tagName == "svg")
 
656
            {
 
657
            newElement = new SVGSVGElementImpl();
 
658
            newElement->assign(*sourceElem);
 
659
            parent->appendChild(newElement);
 
660
            }
 
661
        else if (tagName == "title")
 
662
            {
 
663
            newElement = new SVGTitleElementImpl();
 
664
            newElement->assign(*sourceElem);
 
665
            parent->appendChild(newElement);
 
666
            }
 
667
        else if (tagName == "desc")
 
668
            {
 
669
            newElement = new SVGDescElementImpl();
 
670
            newElement->assign(*sourceElem);
 
671
            parent->appendChild(newElement);
 
672
            }
 
673
        else if (tagName == "defs")
 
674
            {
 
675
            newElement = new SVGDefsElementImpl();
 
676
            newElement->assign(*sourceElem);
 
677
            parent->appendChild(newElement);
 
678
            }
 
679
        else if (tagName == "style")
 
680
            {
 
681
            newElement = new SVGStyleElementImpl();
 
682
            newElement->assign(*sourceElem);
 
683
            parent->appendChild(newElement);
 
684
            }
 
685
        else if (tagName == "g")
 
686
            {
 
687
            newElement = new SVGGElementImpl();
 
688
            newElement->assign(*sourceElem);
 
689
            parent->appendChild(newElement);
 
690
            }
 
691
        else if (tagName == "path")
 
692
            {
 
693
            newElement = new SVGPathElementImpl();
 
694
            newElement->assign(*sourceElem);
 
695
            parent->appendChild(newElement);
 
696
            }
 
697
        }
 
698
 
 
699
    NodeList children = sourceElem->getChildNodes();
 
700
    int nodeCount = children.getLength();
 
701
    for (int i=0 ; i<nodeCount ; i++)
 
702
        {
 
703
        Node *child = children.item(i);
 
704
        int typ = child->getNodeType();
 
705
        if (typ == Node::TEXT_NODE)
 
706
            {
 
707
            Node *newNode = doc->createTextNode(child->getNodeValue());
 
708
            parent->appendChild(newNode);
 
709
            }
 
710
        else if (typ == Node::CDATA_SECTION_NODE)
 
711
            {
 
712
            Node *newNode = doc->createCDATASection(child->getNodeValue());
 
713
            parent->appendChild(newNode);
 
714
            }
 
715
        else if (newElement && typ == Node::ELEMENT_NODE)
 
716
            {
 
717
            ElementImpl *childElement = dynamic_cast<ElementImpl *>(child);
 
718
            parseElement(newElement, childElement);
 
719
            }
 
720
        }
 
721
    return true;
 
722
}
 
723
 
 
724
 
 
725
/**
 
726
 *
 
727
 */
 
728
Document *SvgParser::parse(const Document *sourceDoc)
 
729
{
 
730
    if (!sourceDoc)
 
731
        {
 
732
        error("NULL source document");
 
733
        return NULL;
 
734
        }
 
735
 
 
736
    Document *src = (Document *)sourceDoc;
 
737
    DOMImplementationImpl impl;
 
738
    doc = new SVGDocumentImpl(&impl, SVG_NAMESPACE, "svg" , NULL);
 
739
 
 
740
    ElementImpl *destElem = dynamic_cast<ElementImpl *>(doc->getDocumentElement());
 
741
    ElementImpl *srcElem  = dynamic_cast<ElementImpl *>(src->getDocumentElement());
 
742
    if (!parseElement(destElem, srcElem))
 
743
        {
 
744
        delete doc;
 
745
        return NULL;
 
746
        }
 
747
 
 
748
    return doc;
 
749
}
 
750
 
 
751
 
 
752
 
 
753
 
 
754
}  //namespace svg
 
755
}  //namespace dom
 
756
}  //namespace w3c
 
757
}  //namespace org
 
758
 
 
759
/*#########################################################################
 
760
## E N D    O F    F I L E
 
761
#########################################################################*/
 
762