Code

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