Code

Add new rearranged /dom directory
[inkscape.git] / src / dom / xmlreader.cpp
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     { "&amp;"  , 5 , "&"  },\r
62     { "&lt;"   , 4 , "<"  },\r
63     { "&gt;"   , 4 , ">"  },\r
64     { "&apos;" , 6 , "'"  },\r
65     { "&quot;" , 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(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(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(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(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(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(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(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