1 /**\r
2 * Phoebe DOM Implementation.\r
3 *\r
4 * This is a C++ approximation of the W3C DOM model, which follows\r
5 * fairly closely the specifications in the various .idl files, copies of\r
6 * which are provided for reference. Most important is this one:\r
7 *\r
8 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html\r
9 *\r
10 * Authors:\r
11 * Bob Jamison\r
12 *\r
13 * Copyright (C) 2005 Bob Jamison\r
14 *\r
15 * This library is free software; you can redistribute it and/or\r
16 * modify it under the terms of the GNU Lesser General Public\r
17 * License as published by the Free Software Foundation; either\r
18 * version 2.1 of the License, or (at your option) any later version.\r
19 *\r
20 * This library is distributed in the hope that it will be useful,\r
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
23 * Lesser General Public License for more details.\r
24 *\r
25 * You should have received a copy of the GNU Lesser General Public\r
26 * License along with this library; if not, write to the Free Software\r
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
28 */\r
29 \r
30 \r
31 \r
32 #include "xmlreader.h"\r
33 #include "charclass.h"\r
34 #include "domimpl.h"\r
35 #include "svg/svgimpl.h"\r
36 \r
37 #include <stdio.h>\r
38 #include <stdarg.h>\r
39 \r
40 namespace org\r
41 {\r
42 namespace w3c\r
43 {\r
44 namespace dom\r
45 {\r
46 \r
47 \r
48 //#########################################################################\r
49 //# E N T I T Y T A B L E\r
50 //#########################################################################\r
51 struct EntityInfo\r
52 {\r
53 char *escape;\r
54 int escapeLength;\r
55 char *value;\r
56 };\r
57 \r
58 \r
59 static EntityInfo entityTable[] =\r
60 {\r
61 { "&" , 5 , "&" },\r
62 { "<" , 4 , "<" },\r
63 { ">" , 4 , ">" },\r
64 { "'" , 6 , "'" },\r
65 { """ , 6 , "\"" },\r
66 { NULL , 0 , "\0" }\r
67 };\r
68 \r
69 \r
70 \r
71 //#########################################################################\r
72 //# M E S S A G E S\r
73 //#########################################################################\r
74 \r
75 \r
76 /**\r
77 *\r
78 */\r
79 void XmlReader::error(char *fmt, ...)\r
80 {\r
81 va_list args;\r
82 fprintf(stderr, "XmlReader:error at line %d, column %d:", lineNr, colNr);\r
83 va_start(args, fmt);\r
84 vfprintf(stderr, fmt, args);\r
85 va_end(args) ;\r
86 fprintf(stderr, "\n");\r
87 }\r
88 \r
89 \r
90 \r
91 //#########################################################################\r
92 //# U T I L I T Y\r
93 //#########################################################################\r
94 \r
95 static void trim(DOMString &str)\r
96 {\r
97 int len = str.size();\r
98 if (len<1)\r
99 return;\r
100 \r
101 int start = 0;\r
102 int end = 0;\r
103 for (start=0 ; start<len ; start++)\r
104 {\r
105 int ch = str[start];\r
106 if (ch<=' ' || ch>126)\r
107 break;\r
108 }\r
109 for (end=len-1 ; end>=0 ; end--)\r
110 {\r
111 int ch = str[end];\r
112 if (ch<=' ' || ch>126)\r
113 break;\r
114 }\r
115 if (start<end)\r
116 {\r
117 str = str.substr(start, end+1);\r
118 }\r
119 }\r
120 \r
121 //#########################################################################\r
122 //# P A R S I N G\r
123 //#########################################################################\r
124 \r
125 /**\r
126 * Get the character at the position and record the fact\r
127 */\r
128 int XmlReader::get(int p)\r
129 {\r
130 if (p >= len)\r
131 return -1;\r
132 int ch = parsebuf[p];\r
133 //printf("%c", ch);\r
134 if (ch == '\n' || ch == '\r')\r
135 {\r
136 colNr = 0;\r
137 lineNr++;\r
138 }\r
139 else\r
140 colNr++;\r
141 return ch;\r
142 }\r
143 \r
144 /**\r
145 * Look at the character at the position, but don't note the fact\r
146 */\r
147 int XmlReader::peek(int p)\r
148 {\r
149 if (p >= len)\r
150 return -1;\r
151 int ch = parsebuf[p];\r
152 return ch;\r
153 }\r
154 \r
155 \r
156 /**\r
157 * Test if the given substring exists at the given position\r
158 * in parsebuf. Use peek() in case of out-of-bounds\r
159 */\r
160 bool XmlReader::match(int pos, char *str)\r
161 {\r
162 while (*str)\r
163 {\r
164 if (peek(pos++) != *str++)\r
165 return false;\r
166 }\r
167 return true;\r
168 }\r
169 \r
170 \r
171 \r
172 /**\r
173 * Test if the given substring exists at the given position\r
174 * in a given buffer\r
175 */\r
176 /*\r
177 static bool bufMatch(const DOMString &buf, int pos, char *str)\r
178 {\r
179 while (*str)\r
180 {\r
181 if (buf[pos++] != *str++)\r
182 return false;\r
183 }\r
184 return true;\r
185 }\r
186 */\r
187 \r
188 \r
189 /**\r
190 *\r
191 */\r
192 int XmlReader::skipwhite(int p)\r
193 {\r
194 while (p < len)\r
195 {\r
196 int b = get(p);\r
197 if (!isWhitespace(b))\r
198 break;\r
199 p++;\r
200 }\r
201 return p;\r
202 }\r
203 \r
204 /**\r
205 * modify this to allow all chars for an element or attribute name\r
206 */\r
207 int XmlReader::getWord(int p, DOMString &result)\r
208 {\r
209 while (p<len)\r
210 {\r
211 int b = get(p);\r
212 if (b<=' ' || b=='/' || b=='>' || b=='=')\r
213 break;\r
214 result.push_back((XMLCh)b);\r
215 p++;\r
216 }\r
217 return p;\r
218 }\r
219 \r
220 /**\r
221 * get a name and prefix, if any\r
222 */\r
223 int XmlReader::getPrefixedWord(int p, DOMString &prefix,\r
224 DOMString &shortWord, DOMString &fullWord)\r
225 {\r
226 while (p<len)\r
227 {\r
228 int b = get(p);\r
229 if (b<=' ' || b=='/' || b=='>' || b=='=')\r
230 break;\r
231 else if (b == ':')\r
232 {\r
233 prefix = shortWord;\r
234 shortWord = "";\r
235 }\r
236 else\r
237 shortWord.push_back((XMLCh)b);\r
238 p++;\r
239 }\r
240 if (prefix.size() > 0)\r
241 fullWord = prefix + ":" + shortWord;\r
242 else\r
243 fullWord = shortWord;\r
244 return p;\r
245 }\r
246 \r
247 \r
248 /**\r
249 * Assume that we are starting on a quote. Ends on the char\r
250 * after the final '"'\r
251 */\r
252 int XmlReader::getQuoted(int p0, DOMString &result)\r
253 {\r
254 \r
255 int p = p0;\r
256 \r
257 if (peek(p)!='"' && peek(p)!='\'')\r
258 return p0;\r
259 \r
260 int b = get(p++); //go to next char\r
261 \r
262 DOMString buf;\r
263 \r
264 while (p<len )\r
265 {\r
266 b = get(p++);\r
267 if (b=='"' || b=='\'')\r
268 break;\r
269 else if (b=='&')\r
270 {\r
271 p = parseEntity(p, result);\r
272 if (p < 0)\r
273 return p0;\r
274 }\r
275 else\r
276 {\r
277 buf.push_back((XMLCh)b);\r
278 }\r
279 }\r
280 \r
281 //printf("quoted text:'%s'\n", buf.c_str());\r
282 \r
283 result.append(buf);\r
284 \r
285 return p;\r
286 }\r
287 \r
288 \r
289 \r
290 /**\r
291 * Parse a <!xml> tag. Node may be null. Assumes current char is '<'\r
292 * ends on char after '>'\r
293 */\r
294 int XmlReader::parseVersion(int p0)\r
295 {\r
296 int p = p0;\r
297 \r
298 if (!match(p, "<?xml"))\r
299 return p0;\r
300 \r
301 p += 5;\r
302 colNr += 5;\r
303 \r
304 bool quickCloseDummy;\r
305 Node *node = new NodeImpl();\r
306 int p2 = parseAttributes(p, node, &quickCloseDummy);\r
307 if (p2 < p)\r
308 {\r
309 delete node;\r
310 return p0;\r
311 }\r
312 p = p2;\r
313 \r
314 //get the attributes that we need\r
315 NamedNodeMap attributes = node->getAttributes();\r
316 Node *attr = attributes.getNamedItem("version");\r
317 if (attr)\r
318 document->setXmlVersion(attr->getNodeValue());\r
319 attr = attributes.getNamedItem("encoding");\r
320 if (attr)\r
321 { /*document->setXmlEncoding(attr->getNodeValue());*/ }\r
322 attr = attributes.getNamedItem("standalone");\r
323 if (attr)\r
324 document->setXmlStandalone((attr->getNodeValue() == "yes"));\r
325 delete node;\r
326 \r
327 //#now we should be pointing at '?>'\r
328 if (!match(p, "?>"))\r
329 {\r
330 return p0;\r
331 }\r
332 \r
333 //skip over '?>'\r
334 get(p++);\r
335 get(p++);\r
336 \r
337 return p;\r
338 }\r
339 \r
340 \r
341 /**\r
342 * Parse a <!DOCTYPE> tag. doctype may be null. Expects '<'\r
343 * on start. Ends pointing at char after '>'\r
344 */\r
345 int XmlReader::parseDoctype(int p0)\r
346 {\r
347 int p = p0;\r
348 \r
349 if (!match(p, "<!DOCTYPE"))\r
350 return p0;\r
351 \r
352 p += 9;\r
353 colNr += 9;\r
354 \r
355 DocumentType *doctype = document->getDoctype();\r
356 if (!doctype)\r
357 return p0;\r
358 \r
359 \r
360 //### get the root name of the document\r
361 p = skipwhite(p);\r
362 DOMString rootName;\r
363 int p2 = getWord(p, rootName);\r
364 if (p2 <= p)\r
365 return p0;\r
366 p = p2;\r
367 //printf("doctype root '%s'\n", rootName.c_str());\r
368 \r
369 \r
370 while (p < len)\r
371 {\r
372 p = skipwhite(p);\r
373 if (peek(p) == '>')\r
374 break;\r
375 else if (peek(p) == '[') //just ignore 'internal' [] stuff\r
376 {\r
377 while (p < len)\r
378 {\r
379 int ch = get(p++);\r
380 if (ch == ']')\r
381 break;\r
382 }\r
383 p++;\r
384 }\r
385 else if (match(p, "PUBLIC"))\r
386 {\r
387 p += 6;\r
388 colNr += 6;\r
389 p = skipwhite(p);\r
390 DOMString pubIdLiteral;\r
391 int p2 = getQuoted(p, pubIdLiteral);\r
392 if (p2 <= p)\r
393 return p0;\r
394 p = p2;\r
395 p = skipwhite(p);\r
396 DOMString systemLiteral;\r
397 p2 = getQuoted(p, systemLiteral);\r
398 if (p2 <= p)\r
399 return p0;\r
400 p = p2;\r
401 //printf("PUBLIC \"%s\" \"%s\" \n",\r
402 // pubIdLiteral.c_str(), systemLiteral.c_str());\r
403 }\r
404 else if (match(p, "SYSTEM"))\r
405 {\r
406 p += 6;\r
407 colNr += 6;\r
408 p = skipwhite(p);\r
409 DOMString systemLiteral;\r
410 int p2 = getQuoted(p, systemLiteral);\r
411 if (p2 <= p)\r
412 return p0;\r
413 p = p2;\r
414 //printf("SYSTEM \"%s\" \n", systemLiteral.c_str());\r
415 }\r
416 }\r
417 \r
418 \r
419 //skip over '>'\r
420 get(p++);\r
421 \r
422 return p;\r
423 }\r
424 \r
425 \r
426 \r
427 /**\r
428 * Expects '<' on startup, ends on char after '>'\r
429 */\r
430 int XmlReader::parseComment(int p0, Comment *comment)\r
431 {\r
432 int p = p0;\r
433 \r
434 if (!match(p, "<!--"))\r
435 return p0;\r
436 \r
437 colNr += 4;\r
438 p += 4;\r
439 \r
440 DOMString buf;\r
441 \r
442 while (p<len-3)\r
443 {\r
444 if (match(p, "-->"))\r
445 {\r
446 p += 3;\r
447 colNr += 3;\r
448 break;\r
449 }\r
450 int ch = get(p++);\r
451 buf.push_back((XMLCh)ch);\r
452 }\r
453 \r
454 comment->setNodeValue(buf);\r
455 \r
456 return p;\r
457 }\r
458 \r
459 \r
460 \r
461 /**\r
462 *\r
463 */\r
464 int XmlReader::parseCDATA(int p0, CDATASection *cdata)\r
465 {\r
466 \r
467 int p = p0;\r
468 \r
469 if (!match(p, "<![CDATA["))\r
470 return p0;\r
471 \r
472 colNr += 9;\r
473 p += 9;\r
474 \r
475 DOMString buf;\r
476 \r
477 while (p<len)\r
478 {\r
479 if (match(p, "]]>"))\r
480 {\r
481 p +=3;\r
482 colNr += 3;\r
483 break;\r
484 }\r
485 int ch = get(p++);\r
486 buf.push_back((XMLCh)ch);\r
487 }\r
488 \r
489 /*printf("Got CDATA:%s\n",buf.c_str());*/\r
490 cdata->setNodeValue(buf);\r
491 \r
492 return p;\r
493 }\r
494 \r
495 \r
496 \r
497 /**\r
498 *\r
499 */\r
500 int XmlReader::parseText(int p0, Text *text)\r
501 {\r
502 \r
503 int p = p0;\r
504 \r
505 DOMString buf;\r
506 \r
507 while (p<len)\r
508 {\r
509 if (peek(p) == '&')\r
510 {\r
511 p = parseEntity(p, buf);\r
512 if (p < 0) //error?\r
513 return p0;\r
514 }\r
515 else if (peek(p) == '<')\r
516 {\r
517 break;\r
518 }\r
519 else\r
520 {\r
521 int ch = get(p++);\r
522 buf.push_back((XMLCh)ch);\r
523 }\r
524 }\r
525 \r
526 /*printf("Got Text:%s\n",buf.c_str());*/\r
527 text->setNodeValue(buf);\r
528 \r
529 return p;\r
530 }\r
531 \r
532 \r
533 \r
534 \r
535 \r
536 /**\r
537 * Parses attributes of a node. Should end pointing at either the\r
538 * '?' of a version or doctype tag, or a '>' of a normal tag\r
539 */\r
540 int XmlReader::parseAttributes(int p0, Node *node, bool *quickClose)\r
541 {\r
542 *quickClose = false;\r
543 \r
544 int p = p0;\r
545 \r
546 NamedNodeMap attributes;\r
547 \r
548 while (p<len)\r
549 {\r
550 /*printf("ch:%c\n",ch);*/\r
551 p = skipwhite(p);\r
552 int ch = get(p);\r
553 \r
554 /*printf("ch:%c\n",ch);*/\r
555 if (ch == '?' || ch == '>')//done\r
556 break;\r
557 else if (ch=='/' && p<len+1)\r
558 {\r
559 p++;\r
560 p = skipwhite(p);\r
561 ch = peek(p);\r
562 if (ch == '>')\r
563 {\r
564 p++;\r
565 *quickClose = true;\r
566 /*printf("quick close\n");*/\r
567 return p;\r
568 }\r
569 }\r
570 DOMString shortName;\r
571 DOMString prefix;\r
572 DOMString qualifiedName;\r
573 int p2 = getPrefixedWord(p, prefix, shortName, qualifiedName);\r
574 if (p2 <= p)\r
575 break;\r
576 \r
577 /*printf("name:%s",buf);*/\r
578 p = p2;\r
579 p = skipwhite(p);\r
580 ch = get(p);\r
581 /*printf("ch:%c\n",ch);*/\r
582 if (ch != '=')\r
583 break;\r
584 p++;\r
585 p = skipwhite(p);\r
586 /*ch = parsebuf[p];*/\r
587 /*printf("ch:%c\n",ch);*/\r
588 DOMString attrValue;\r
589 p2 = getQuoted(p, attrValue);\r
590 p = p2;\r
591 /*printf("name:'%s' value:'%s'\n",buf,buf2);*/\r
592 \r
593 DOMString namespaceURI = "";\r
594 if (prefix == "xmlns" || shortName == "xmlns")\r
595 namespaceURI = XMLNSNAME;\r
596 \r
597 //## Now let us make the attribute and give it to the node\r
598 Attr *attr = document->createAttributeNS(namespaceURI, qualifiedName);\r
599 attr->setValue(attrValue);\r
600 node->getAttributes().setNamedItemNS(attr);\r
601 \r
602 }//while p<len\r
603 \r
604 return p;\r
605 }\r
606 \r
607 /**\r
608 * Appends the value of an entity to the buffer\r
609 */\r
610 int XmlReader::parseEntity(int p0, DOMString &buf)\r
611 {\r
612 int p = p0;\r
613 for (EntityInfo *info = entityTable ; info->escape ; info++)\r
614 {\r
615 if (match(p, info->escape))\r
616 {\r
617 p += info->escapeLength;\r
618 colNr += info->escapeLength;\r
619 buf += info->value;\r
620 return p;\r
621 }\r
622 }\r
623 \r
624 error("unterminated entity");\r
625 return -1;\r
626 }\r
627 \r
628 \r
629 //#########################################################################\r
630 //# P A R S E A N O D E\r
631 //#########################################################################\r
632 \r
633 /**\r
634 * Parse as a document, preserving the original structure as much as\r
635 * possible\r
636 */\r
637 int XmlReader::parseNode(int p0, Node *node, int depth)\r
638 {\r
639 \r
640 int p = p0;\r
641 \r
642 \r
643 //### OPEN TAG\r
644 int ch = get(p++);\r
645 if (ch != '<')\r
646 return p0;\r
647 \r
648 p = skipwhite(p);\r
649 DOMString openTagName;\r
650 DOMString openTagNamePrefix;\r
651 DOMString openTagQualifiedName;\r
652 int p2 = getPrefixedWord(p,openTagNamePrefix,\r
653 openTagName, openTagQualifiedName);\r
654 if (p2 <= p)\r
655 return p0;\r
656 p = p2;\r
657 p = skipwhite(p);\r
658 \r
659 //printf("qualifiedName:%s\n", openTagQualifiedName.c_str());\r
660 DOMString namespaceURI = node->lookupNamespaceURI(openTagNamePrefix);\r
661 document->renameNode(node, namespaceURI, openTagQualifiedName);\r
662 \r
663 //### ATTRIBUTES\r
664 bool quickClose;\r
665 p = parseAttributes(p, node, &quickClose);\r
666 if (quickClose) //trivial tag: <name/>\r
667 return p;\r
668 \r
669 p++; //skip over '>'\r
670 \r
671 \r
672 DOMString nodeValue;\r
673 \r
674 /* ### Get intervening data ### */\r
675 while (p<len && keepGoing)\r
676 {\r
677 //### COMMENT\r
678 if (match(p, "<!--"))\r
679 {\r
680 Comment *comment = document->createComment("");\r
681 p2 = parseComment(p, comment);\r
682 if (p2 <= p)\r
683 return p0;\r
684 p = p2;\r
685 if (parseAsData)\r
686 { //throw away\r
687 delete comment;\r
688 }\r
689 else\r
690 {\r
691 node->appendChild(comment);\r
692 }\r
693 }\r
694 //### VERSION\r
695 else if (match(p, "<?xml"))\r
696 {\r
697 p2 = parseVersion(p);\r
698 if (p2 <= p)\r
699 return p0;\r
700 }\r
701 //### DOCTYPE\r
702 else if (match(p, "<!DOCTYPE"))\r
703 {\r
704 p2 = parseDoctype(p);\r
705 if (p2 <= p)\r
706 return p0;\r
707 }\r
708 //### CDATA\r
709 else if (match(p, "<![CDATA["))\r
710 {\r
711 CDATASection *cdata = document->createCDATASection("");\r
712 p2 = parseCDATA(p, cdata);\r
713 if (p2 <= p)\r
714 return p0;\r
715 p = p2;\r
716 if (parseAsData)\r
717 {\r
718 nodeValue += cdata->getNodeValue();\r
719 delete cdata;\r
720 }\r
721 else\r
722 {\r
723 node->appendChild(cdata);\r
724 }\r
725 }\r
726 //### OPEN OR CLOSE TAG\r
727 else if (peek(p) == '<')\r
728 {\r
729 p2 = skipwhite(p+1);\r
730 if (peek(p2) =='/')\r
731 {\r
732 p = p2;\r
733 break;\r
734 }\r
735 else\r
736 {\r
737 /*Add element to tree*/\r
738 Element *elem = document->createElement(""); //fill in name later\r
739 node->appendChild(elem);\r
740 p2 = parseNode(p, elem, depth+1);\r
741 if (p2 <= p)\r
742 {\r
743 /*printf("problem on element:%ls. p2:%d p:%d\n",n->name, p2, p);*/\r
744 return p0;\r
745 }\r
746 p = p2;\r
747 }\r
748 }\r
749 //### TEXT\r
750 else\r
751 {\r
752 Text *text = document->createTextNode("");\r
753 p2 = parseText(p, text);\r
754 if (p2 <= p)\r
755 return p0;\r
756 p = p2;\r
757 if (parseAsData)\r
758 {\r
759 nodeValue += text->getNodeValue();\r
760 delete text;\r
761 }\r
762 else\r
763 {\r
764 node->appendChild(text);\r
765 }\r
766 }\r
767 \r
768 }//while (p<len)\r
769 \r
770 //printf("%d : nodeValue:'%s'\n", p, nodeValue.c_str());\r
771 trim(nodeValue);\r
772 node->setNodeValue(nodeValue);\r
773 \r
774 //### get close tag. we should be pointing at '/'\r
775 p = skipwhite(p);\r
776 ch = get(p);\r
777 if (ch != '/')\r
778 {\r
779 error("no / on end tag");\r
780 return p0;\r
781 }\r
782 p++;\r
783 \r
784 //### get word after '/'\r
785 p = skipwhite(p);\r
786 DOMString closeTagName;\r
787 DOMString closeTagNamePrefix;\r
788 DOMString closeTagQualifiedName;\r
789 p = getPrefixedWord(p, closeTagNamePrefix, closeTagName,\r
790 closeTagQualifiedName);\r
791 if (openTagQualifiedName != closeTagQualifiedName)\r
792 {\r
793 error("Mismatched closing tag. Expected </%S>. Got '%S'.",\r
794 openTagQualifiedName.c_str(), closeTagQualifiedName.c_str());\r
795 return p0;\r
796 }\r
797 p = skipwhite(p);\r
798 if (parsebuf[p] != '>')\r
799 {\r
800 error("no > on end tag");\r
801 return p0;\r
802 }\r
803 p++;\r
804 /*printf("close element:%ls\n",buf);*/\r
805 return p;\r
806 }\r
807 \r
808 \r
809 /**\r
810 *\r
811 */\r
812 org::w3c::dom::Document *\r
813 XmlReader::parse(const DOMString &buf, int bufferOffset, int parseLen)\r
814 {\r
815 len = parseLen;\r
816 parsebuf = buf;\r
817 \r
818 DOMImplementationSourceImpl source;\r
819 DOMImplementation *domImpl = source.getDOMImplementation("");\r
820 \r
821 keepGoing = true;\r
822 \r
823 document = domImpl->createDocument("", "", NULL);\r
824 //document = new svg::SVGDocumentImpl(domImpl, "", "", NULL);\r
825 \r
826 int p = bufferOffset;\r
827 int p2 = 0;\r
828 \r
829 while (p<len && keepGoing)\r
830 {\r
831 p = skipwhite(p);\r
832 //### COMMENT\r
833 if (match(p, "<!--"))\r
834 {\r
835 Comment *comment = document->createComment("");\r
836 p2 = parseComment(p, comment);\r
837 if (p2 <= p)\r
838 return document;\r
839 p = p2;\r
840 if (parseAsData)\r
841 { //throw away\r
842 delete comment;\r
843 }\r
844 else\r
845 {\r
846 document->appendChild(comment);\r
847 }\r
848 }\r
849 //### VERSION\r
850 else if (match(p, "<?xml"))\r
851 {\r
852 p2 = parseVersion(p);\r
853 if (p2 <= p)\r
854 return document;\r
855 p = p2;\r
856 }\r
857 //### DOCTYPE\r
858 else if (match(p, "<!DOCTYPE"))\r
859 {\r
860 p2 = parseDoctype(p);\r
861 if (p2 <= p)\r
862 return document;\r
863 p = p2;\r
864 }\r
865 else\r
866 {\r
867 break;\r
868 }\r
869 }\r
870 \r
871 p = skipwhite(p);\r
872 p = parseNode(p, document->getDocumentElement(), 0);\r
873 \r
874 keepGoing = false;\r
875 \r
876 return document;\r
877 }\r
878 \r
879 \r
880 /**\r
881 *\r
882 */\r
883 org::w3c::dom::Document *\r
884 XmlReader::parse(const DOMString &str)\r
885 {\r
886 \r
887 Document *doc = parse(str, 0, str.size());\r
888 doc->normalizeDocument();\r
889 \r
890 return doc;\r
891 }\r
892 \r
893 /**\r
894 *\r
895 */\r
896 org::w3c::dom::Document *\r
897 XmlReader::parseFile(char *fileName)\r
898 {\r
899 \r
900 DOMString buf = loadFile(fileName);\r
901 \r
902 Document *doc = parse(buf, 0, buf.size());\r
903 \r
904 return doc;\r
905 }\r
906 \r
907 \r
908 \r
909 //#########################################################################\r
910 //# S T R E A M R E A D I N G\r
911 //#########################################################################\r
912 \r
913 /**\r
914 *\r
915 */\r
916 org::w3c::dom::DOMString\r
917 XmlReader::loadFile(char *fileName)\r
918 {\r
919 \r
920 if (!fileName)\r
921 return NULL;\r
922 FILE *f = fopen(fileName, "rb");\r
923 if (!f)\r
924 return NULL;\r
925 \r
926 DOMString buf;\r
927 while (!feof(f))\r
928 {\r
929 int ch = fgetc(f);\r
930 if (ch<0)\r
931 break;\r
932 buf.push_back((XMLCh)ch);\r
933 }\r
934 fclose(f);\r
935 \r
936 return buf;\r
937 }\r
938 \r
939 \r
940 //#########################################################################\r
941 //# C O N S T R U C T O R / D E S T R U C T O R\r
942 //#########################################################################\r
943 \r
944 \r
945 /**\r
946 *\r
947 */\r
948 XmlReader::XmlReader()\r
949 {\r
950 len = 0;\r
951 lineNr = 1;\r
952 colNr = 0;\r
953 parseAsData = false;\r
954 keepGoing = false;\r
955 }\r
956 \r
957 /**\r
958 *\r
959 */\r
960 XmlReader::XmlReader(bool parseAsDataArg)\r
961 {\r
962 len = 0;\r
963 lineNr = 1;\r
964 colNr = 0;\r
965 parseAsData = parseAsDataArg;\r
966 keepGoing = false;\r
967 }\r
968 \r
969 \r
970 \r
971 /**\r
972 *\r
973 */\r
974 XmlReader::~XmlReader()\r
975 {\r
976 }\r
977 \r
978 \r
979 } //namespace dom\r
980 } //namespace w3c\r
981 } //namespace org\r
982 \r
983 \r
984 //#########################################################################\r
985 //# E N D O F F I L E\r
986 //#########################################################################\r
987 \r