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;
106 }
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)
115 {
116 while (*str)
117 {
118 if (get(pos++) != (XMLCh) *str++)
119 return false;
120 }
121 return true;
122 }
124 /**
125 *
126 */
127 int SVGReader::skipwhite(int p)
128 {
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;
182 }
184 /**
185 * get a word from the buffer
186 */
187 int SVGReader::getWord(int p, DOMString &result)
188 {
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;
213 }
216 # if 0
217 /**
218 * get a word from the buffer
219 */
220 int SVGReader::getNumber(int p0, double &result)
221 {
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;
267 }
268 #endif
271 /**
272 * get a word from the buffer
273 */
274 int SVGReader::getNumber(int p0, double &result)
275 {
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;
300 }
303 bool SVGReader::parseTransform(const DOMString &str)
304 {
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;
612 }
615 /**
616 *
617 */
618 bool SVGReader::parseElement(SVGElementImplPtr parent,
619 ElementImplPtr sourceElem)
620 {
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;
673 }
676 /**
677 *
678 */
679 SVGDocumentPtr SVGReader::parse(const DocumentPtr src)
680 {
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;
698 }
702 /**
703 *
704 */
705 SVGDocumentPtr SVGReader::parse(const DOMString &buf)
706 {
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;
717 }
721 /**
722 *
723 */
724 SVGDocumentPtr SVGReader::parseFile(const DOMString &fileName)
725 {
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;
737 }
742 } //namespace svg
743 } //namespace dom
744 } //namespace w3c
745 } //namespace org
747 /*#########################################################################
748 ## E N D O F F I L E
749 #########################################################################*/