Code

Patch from Lubomir Rintel: fixes for GCC 4.4
[inkscape.git] / src / dom / svgreader.cpp
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-2008 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  * NOTES
31  * 
32  *      
33  */
36 #include "svgreader.h"
37 #include "dom/cssreader.h"
38 #include "dom/ucd.h"
39 #include "xmlreader.h"
41 #include <cstdio>
42 #include <stdarg.h>
45 namespace org
46 {
47 namespace w3c
48 {
49 namespace dom
50 {
51 namespace svg
52 {
55 //#########################################################################
56 //# M E S S A G E S
57 //#########################################################################
60 /**
61  *
62  */
63 void SVGReader::error(char const *fmt, ...)
64 {
65     va_list args;
66     fprintf(stderr, "SVGReader:error: ");
67     va_start(args, fmt);
68     vfprintf(stderr, fmt, args);
69     va_end(args) ;
70     fprintf(stderr, "\n");
71 }
74 /**
75  *
76  */
77 void SVGReader::trace(char const *fmt, ...)
78 {
79     va_list args;
80     fprintf(stdout, "SVGReader: ");
81     va_start(args, fmt);
82     vfprintf(stdout, fmt, args);
83     va_end(args) ;
84     fprintf(stdout, "\n");
85 }
89 //#########################################################################
90 //# P A R S I N G
91 //#########################################################################
95 /**
96  *  Get the character at the position and record the fact
97  */
98 XMLCh SVGReader::get(int p)
99 {
100     if (p >= parselen)
101         return 0;
102     XMLCh ch = parsebuf[p];
103     //printf("%c", ch);
104     lastPosition = p;
105     return ch;
110 /**
111  *  Test if the given substring exists at the given position
112  *  in parsebuf.  Use get() in case of out-of-bounds
113  */
114 bool SVGReader::match(int pos, char const *str)
116     while (*str)
117        {
118        if (get(pos++) != (XMLCh) *str++)
119            return false;
120        }
121    return true;
124 /**
125  *
126  */
127 int SVGReader::skipwhite(int p)
129   while (p < parselen)
130     {
131     //# XML COMMENT
132     if (match(p, "<!--"))
133         {
134         p+=4;
135         bool done=false;
136         while (p<parselen)
137             {
138             if (match(p, "-->"))
139                 {
140                 p+=3;
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     //# C comment
154     else if (match(p, "/*"))
155         {
156         p+=2;
157         bool done=false;
158         while (p<parselen)
159             {
160             if (match(p, "*/"))
161                 {
162                 p+=2;
163                 done=true;
164                 break;
165                 }
166             p++;
167             }
168         lastPosition = p;
169         if (!done)
170             {
171             error("unterminated /* .. */ comment");
172             return -1;
173             }
174         }
175     else if (!uni_is_space(get(p)))
176         break;
177     else
178         p++;
179     }
180   lastPosition = p;
181   return p;
184 /**
185  * get a word from the buffer
186  */
187 int SVGReader::getWord(int p, DOMString &result)
189     XMLCh ch = get(p);
190     if (!uni_is_letter(ch))
191         return p;
192     DOMString str;
193     str.push_back(ch);
194     p++;
196     while (p < parselen)
197         {
198         ch = get(p);
199         if (uni_is_letter_or_digit(ch) || ch=='-' || ch=='_')
200             {
201             str.push_back(ch);
202             p++;
203             }
204         else if (ch == '\\')
205             {
206             p+=2;
207             }
208         else
209             break;
210         }
211     result = str;
212     return p;
216 # if 0
217 /**
218  * get a word from the buffer
219  */
220 int SVGReader::getNumber(int p0, double &result)
222     int p=p0;
224     DOMString str;
226     //allow sign
227     if (get(p) == '-')
228         {
229         p++;
230         }
232     while (p < parselen)
233         {
234         XMLCh ch = get(p);
235         if (ch<'0' || ch>'9')
236             break;
237         str.push_back(ch);
238         p++;
239         }
240     if (get(p) == '.' && get(p+1)>='0' && get(p+1)<='9')
241         {
242         p++;
243         str.push_back('.');
244         while (p < parselen)
245             {
246             XMLCh ch = get(p);
247             if (ch<'0' || ch>'9')
248                 break;
249             str.push_back(ch);
250             p++;
251             }
252         }
253     if (p>p0)
254         {
255         char *start = (char *)str.c_str();
256         char *end   = NULL;
257         double val = strtod(start, &end);
258         if (end > start)
259             {
260             result = val;
261             return p;
262             }
263         }
265     //not a number
266     return p0;
268 #endif
271 /**
272  * get a word from the buffer
273  */
274 int SVGReader::getNumber(int p0, double &result)
276     int p=p0;
278     char buf[64];
280     int i;
281     for (i=0 ; i<63 && p<parselen ; i++)
282         {
283         buf[i] = (char) get(p++);
284         }
285     buf[i] = '\0';
287     char *start = buf;
288     char *end   = NULL;
289     double val = strtod(start, &end);
290     if (end > start)
291         {
292         result = val;
293         int count = (int)(end - start);
294         p = p0 + count;
295         return p;
296         }
298     //not a number
299     return p0;
303 bool SVGReader::parseTransform(const DOMString &str)
305     parsebuf = str;
306     parselen = str.size();
308     //printf("transform:%s\n", str.c_str());
310     SVGTransformList transformList;
312     int p = 0;
314     while (p < parselen)
315         {
316         p = skipwhite(p);
317         DOMString name;
318         int p2 = getWord(p, name);
319         if (p2<0)
320             return false;
321         if (p2<=p)
322             {
323             error("transform: need transform name");
324             //return false;
325             break;
326             }
327         p = p2;
328         //printf("transform name:%s\n", name.c_str());
330         //######### MATRIX
331         if (name == "matrix")
332             {
333             p = skipwhite(p);
334             if (get(p++) != '(')
335                 {
336                 error("matrix transform needs opening '('");
337                 return false;
338                 }
339             int nrVals = 0;
340             double vals[6];
341             bool seenBrace = false;
342             while (p < parselen && nrVals < 6)
343                 {
344                 p = skipwhite(p);
345                 double val = 0.0;
346                 p2 = getNumber(p, val);
347                 if (p2<0)
348                     return false;
349                 if (p2<=p)
350                     {
351                     error("matrix() expected number");
352                     return false;
353                     }
354                 vals[nrVals++] = val;
355                 p = skipwhite(p2);
356                 XMLCh ch = get(p);
357                 if (ch == ',')
358                     {
359                     p++;
360                     p = skipwhite(p);
361                     ch = get(p);
362                     }
363                 if (ch == ')')
364                     {
365                     seenBrace = true;
366                     p++;
367                     break;
368                     }
369                 }
370             if (!seenBrace)
371                 {
372                 error("matrix() needs closing brace");
373                 return false;
374                 }
375             if (nrVals != 6)
376                 {
377                 error("matrix() requires exactly 6 arguments");
378                 return false;
379                 }
380             //We got our arguments
381             //printf("translate: %f %f %f %f %f %f\n",
382             //      vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
383             SVGMatrix matrix(vals[0], vals[1], vals[2],
384                              vals[3], vals[4], vals[5]);
385             SVGTransform transform;
386             transform.setMatrix(matrix);
387             transformList.appendItem(transform);
388             }
390         //######### TRANSLATE
391         else if (name == "translate")
392             {
393             p = skipwhite(p);
394             if (get(p++) != '(')
395                 {
396                 error("matrix transform needs opening '('");
397                 return false;
398                 }
399             p = skipwhite(p);
400             double x = 0.0;
401             p2 = getNumber(p, x);
402             if (p2<0)
403                 return false;
404             if (p2<=p)
405                 {
406                 error("translate() expected 'x' value");
407                 return false;
408                 }
409             p = skipwhite(p2);
410             if (get(p) == ',')
411                 {
412                 p++;
413                 p = skipwhite(p);
414                 }
415             double y = 0.0;
416             p2 = getNumber(p, y);
417             if (p2<0)
418                 return false;
419             if (p2<=p) //no y specified. use default
420                 y = 0.0;
421             p = skipwhite(p2);
422             if (get(p++) != ')')
423                 {
424                 error("translate() needs closing ')'");
425                 return false;
426                 }
427             //printf("translate: %f %f\n", x, y);
428             SVGTransform transform;
429             transform.setTranslate(x, y);
430             transformList.appendItem(transform);
431             }
433         //######### SCALE
434         else if (name == "scale")
435             {
436             p = skipwhite(p);
437             if (get(p++) != '(')
438                 {
439                 error("scale transform needs opening '('");
440                 return false;
441                 }
442             p = skipwhite(p);
443             double x = 0.0;
444             p2 = getNumber(p, x);
445             if (p2<0)
446                 return false;
447             if (p2<=p)
448                 {
449                 error("scale() expected 'x' value");
450                 return false;
451                 }
452             p = skipwhite(p2);
453             if (get(p) == ',')
454                 {
455                 p++;
456                 p = skipwhite(p);
457                 }
458             double y = 0.0;
459             p2 = getNumber(p, y);
460             if (p2<0)
461                 return false;
462             if (p2<=p) //no y specified. use default
463                 y = x; // y is same as x.  uniform scaling
464             p = skipwhite(p2);
465             if (get(p++) != ')')
466                 {
467                 error("scale() needs closing ')'");
468                 return false;
469                 }
470             //printf("scale: %f %f\n", x, y);
471             SVGTransform transform;
472             transform.setScale(x, y);
473             transformList.appendItem(transform);
474             }
476         //######### ROTATE
477         else if (name == "rotate")
478             {
479             p = skipwhite(p);
480             if (get(p++) != '(')
481                 {
482                 error("rotate transform needs opening '('");
483                 return false;
484                 }
485             p = skipwhite(p);
486             double angle = 0.0;
487             p2 = getNumber(p, angle);
488             if (p2<0)
489                 return false;
490             if (p2<=p)
491                 {
492                 error("rotate() expected 'angle' value");
493                 return false;
494                 }
495             p = skipwhite(p2);
496             if (get(p) == ',')
497                 {
498                 p++;
499                 p = skipwhite(p);
500                 }
501             double cx = 0.0;
502             double cy = 0.0;
503             p2 = getNumber(p, cx);
504             if (p2>p)
505                 {
506                 p = skipwhite(p2);
507                 if (get(p) == ',')
508                     {
509                     p++;
510                     p = skipwhite(p);
511                     }
512                 p2 = getNumber(p, cy);
513                 if (p2<0)
514                     return false;
515                 if (p2<=p)
516                     {
517                     error("rotate() arguments should be either rotate(angle) or rotate(angle, cx, cy)");
518                     return false;
519                     }
520                 p = skipwhite(p2);
521                 }
522             if (get(p++) != ')')
523                 {
524                 error("rotate() needs closing ')'");
525                 return false;
526                 }
527             //printf("rotate: %f %f %f\n", angle, cx, cy);
528             SVGTransform transform;
529             transform.setRotate(angle, cx, cy);
530             transformList.appendItem(transform);
531             }
533         //######### SKEWX
534         else if (name == "skewX")
535             {
536             p = skipwhite(p);
537             if (get(p++) != '(')
538                 {
539                 error("skewX transform needs opening '('");
540                 return false;
541                 }
542             p = skipwhite(p);
543             double x = 0.0;
544             p2 = getNumber(p, x);
545             if (p2<0)
546                 return false;
547             if (p2<=p)
548                 {
549                 error("skewX() expected 'x' value");
550                 return false;
551                 }
552             p = skipwhite(p2);
553             if (get(p++) != ')')
554                 {
555                 error("skewX() needs closing ')'");
556                 return false;
557                 }
558             //printf("skewX: %f\n", x);
559             SVGTransform transform;
560             transform.setSkewX(x);
561             transformList.appendItem(transform);
562             }
564         //######### SKEWY
565         else if (name == "skewY")
566             {
567             p = skipwhite(p);
568             if (get(p++) != '(')
569                 {
570                 error("skewY transform needs opening '('");
571                 return false;
572                 }
573             p = skipwhite(p);
574             double y = 0.0;
575             p2 = getNumber(p, y);
576             if (p2<0)
577                 return false;
578             if (p2<=p)
579                 {
580                 error("skewY() expected 'y' value");
581                 return false;
582                 }
583             p = skipwhite(p2);
584             if (get(p++) != ')')
585                 {
586                 error("skewY() needs closing ')'");
587                 return false;
588                 }
589             //printf("skewY: %f\n", y);
590             SVGTransform transform;
591             transform.setSkewY(y);
592             transformList.appendItem(transform);
593             }
595         //### NONE OF THE ABOVE
596         else
597             {
598             error("unknown transform type:'%s'", name.c_str());
599             }
601         p = skipwhite(p);
602         XMLCh ch = get(p);
603         if (ch == ',')
604             {
605             p++;
606             p = skipwhite(p);
607             }
609         }//WHILE p<parselen
611     return true;
615 /**
616  *
617  */
618 bool SVGReader::parseElement(SVGElementImplPtr parent,
619                              ElementImplPtr sourceElem)
621     if (!parent)
622         {
623         error("NULL dest element");
624         return false;
625         }
626     if (!sourceElem)
627         {
628         error("NULL source element");
629         return false;
630         }
632     DOMString namespaceURI = sourceElem->getNamespaceURI();
633     //printf("namespaceURI:%s\n", namespaceURI.c_str());
634     DOMString tagName      = sourceElem->getTagName();
635     printf("tag name:%s\n", tagName.c_str());
636     ElementPtr newElement = doc->createElementNS(namespaceURI, tagName);
637     if (!newElement)
638         {
639                 return false;
640                 }
641         NamedNodeMap &attrs = sourceElem->getAttributes();
642         for (unsigned int i=0 ; i<attrs.getLength() ; i++)
643             {
644             NodePtr n = attrs.item(i);
645             newElement->setAttribute(n->getNodeName(), n->getNodeValue());//should be exception here
646                 }
647         parent->appendChild(newElement);
650     NodeList children = sourceElem->getChildNodes();
651     int nodeCount = children.getLength();
652     for (int i=0 ; i<nodeCount ; i++)
653         {
654         NodePtr child = children.item(i);
655         int typ = child->getNodeType();
656         if (typ == Node::TEXT_NODE)
657             {
658             NodePtr newNode = doc->createTextNode(child->getNodeValue());
659             parent->appendChild(newNode);
660             }
661         else if (typ == Node::CDATA_SECTION_NODE)
662             {
663             NodePtr newNode = doc->createCDATASection(child->getNodeValue());
664             parent->appendChild(newNode);
665             }
666         else if (newElement.get() && typ == Node::ELEMENT_NODE)
667             {
668             //ElementImplPtr childElement = dynamic_cast<ElementImpl *>(child.get());
669             //parseElement(newElement, childElement);
670             }
671         }
672     return true;
676 /**
677  *
678  */
679 SVGDocumentPtr SVGReader::parse(const DocumentPtr src)
681     if (!src)
682         {
683         error("NULL source document");
684         return NULL;
685         }
687     DOMImplementationImpl impl;
688     doc = new SVGDocumentImpl(&impl, SVG_NAMESPACE, "svg" , NULL);
690     SVGElementImplPtr destElem = dynamic_pointer_cast<SVGElementImpl, SVGElement>(doc->getRootElement());
691     ElementImplPtr    srcElem  = dynamic_pointer_cast<ElementImpl, Element>(src->getDocumentElement());
692     if (!parseElement(destElem, srcElem))
693         {
694         return NULL;
695         }
697     return doc;
702 /**
703  *
704  */
705 SVGDocumentPtr SVGReader::parse(const DOMString &buf)
707     /* remember, smartptrs are null-testable*/
708     SVGDocumentPtr svgdoc;
709     XmlReader parser;
710     DocumentPtr doc = parser.parse(buf);
711     if (!doc)
712         {
713         return svgdoc;
714         }
715     svgdoc = parse(doc);
716     return svgdoc;
721 /**
722  *
723  */
724 SVGDocumentPtr SVGReader::parseFile(const DOMString &fileName)
726     /* remember, smartptrs are null-testable*/
727     SVGDocumentPtr svgdoc;
728     XmlReader parser;
729     DocumentPtr doc = parser.parseFile(fileName);
730     if (!doc)
731         {
732         error("Could not load xml doc");
733         return svgdoc;
734         }
735     svgdoc = parse(doc);
736     return svgdoc;
742 }  //namespace svg
743 }  //namespace dom
744 }  //namespace w3c
745 }  //namespace org
747 /*#########################################################################
748 ## E N D    O F    F I L E
749 #########################################################################*/