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;
105 }
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)
114 {
115 while (*str)
116 {
117 if (get(pos++) != (XMLCh) *str++)
118 return false;
119 }
120 return true;
121 }
123 /**
124 *
125 */
126 int SVGReader::skipwhite(int p)
127 {
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;
181 }
183 /**
184 * get a word from the buffer
185 */
186 int SVGReader::getWord(int p, DOMString &result)
187 {
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;
212 }
215 # if 0
216 /**
217 * get a word from the buffer
218 */
219 int SVGReader::getNumber(int p0, double &result)
220 {
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;
266 }
267 #endif
270 /**
271 * get a word from the buffer
272 */
273 int SVGReader::getNumber(int p0, double &result)
274 {
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;
299 }
302 bool SVGReader::parseTransform(const DOMString &str)
303 {
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;
611 }
614 /**
615 *
616 */
617 bool SVGReader::parseElement(SVGElementImplPtr parent,
618 ElementImplPtr sourceElem)
619 {
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;
672 }
675 /**
676 *
677 */
678 SVGDocumentPtr SVGReader::parse(const DocumentPtr src)
679 {
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;
697 }
701 /**
702 *
703 */
704 SVGDocumentPtr SVGReader::parse(const DOMString &buf)
705 {
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;
716 }
720 /**
721 *
722 */
723 SVGDocumentPtr SVGReader::parseFile(const DOMString &fileName)
724 {
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;
736 }
741 } //namespace svg
742 } //namespace dom
743 } //namespace w3c
744 } //namespace org
746 /*#########################################################################
747 ## E N D O F F I L E
748 #########################################################################*/