parse_xml.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00039 #include <math.h>
00040 
00041 #include <exception>
00042 #include <string>
00043 #include <vector>
00044 #include <map>
00045 
00046 // XML parser library
00047 #include <expat.h>
00048 
00049 #include <archon/util/term.H>
00050 #include <archon/util/time.H>
00051 #include <archon/util/parse_values.H>
00052 #include <archon/util/text.H>
00053 #include <archon/util/image.H>
00054 
00055 #include <archon/x3d/server/field_type.H>
00056 #include <archon/x3d/server/custom_field.H>
00057 #include <archon/x3d/server/server.H>
00058 #include <archon/x3d/server/parse_xml.H>
00059 
00060 using namespace std;
00061 
00062 namespace Archon
00063 {
00064   using namespace Math;
00065   using namespace Utilities;
00066 
00067   namespace X3D
00068   {
00069     namespace XML
00070     {
00071       struct Parser: X3D::Parser
00072       {
00073         XML_Parser xmlParser;
00074         ProgressTracker *progressTracker;
00075         Time creationTimeStamp;
00076         bool progressive;
00077 
00078         enum Element
00079         {
00080           elem_nil,      // An unrecognized or invalid element
00081           elem_toplevel, // The special element always in bottom of the stack
00082           elem_x3d,
00083           elem_head,
00084           elem_meta,
00085           elem_component,
00086           elem_scene,
00087           elem_route,
00088           elem_proto,
00089           elem_field,
00090           elem_node,     // An element corresponding to a X3D node
00091           elem_use       // An element exploiting the USE attribute
00092         };
00093 
00094         struct StackEntry
00095         {
00096           Element element;
00097 
00102           Ref<NodeBase> node;
00103 
00108           Ref<CustomFieldBase> field;
00109 
00110           const NodeFieldBase *containerField;
00111 
00112           int containerStackIndex;
00113 
00118           string cdata;
00119 
00120           StackEntry(): element(elem_nil), containerField(0), containerStackIndex(-1) {}
00121         };
00122 
00123         string getElementName(Element e, const NodeType *t = 0)
00124         {
00125           switch(e)
00126           {
00127           case elem_nil:       return "(nil)";
00128           case elem_toplevel:  return "(toplevel)";
00129           case elem_x3d:       return "X3D";
00130           case elem_head:      return "head";
00131           case elem_meta:      return "meta";
00132           case elem_component: return "component";
00133           case elem_scene:     return "Scene";
00134           case elem_route:     return "ROUTE";
00135           case elem_proto:     return "PROTO";
00136           case elem_field:     return "field";
00137           case elem_node:      return t ? t->getName() : "(node)";
00138           case elem_use:       return t ? t->getName() : "(use)";
00139           }
00140           ARCHON_THROW1(ArgumentException,
00141                         "Invalid element type");
00142         }
00143 
00144         string getElementName(const StackEntry &e)
00145         {
00146           return getElementName(e.element, e.node ? e.node->getType() : 0);
00147         }
00148 
00157         Element elementLookup(string name)
00158         {
00159           if(Text::compareIgnoreCase(name, "X3D"      )==0) return elem_x3d;
00160           if(Text::compareIgnoreCase(name, "head"     )==0) return elem_head;
00161           if(Text::compareIgnoreCase(name, "meta"     )==0) return elem_meta;
00162           if(Text::compareIgnoreCase(name, "component")==0) return elem_component;
00163           if(Text::compareIgnoreCase(name, "Scene"    )==0) return elem_scene;
00164           if(Text::compareIgnoreCase(name, "ROUTE"    )==0) return elem_route;
00165           if(Text::compareIgnoreCase(name, "PROTO"    )==0) return elem_proto;
00166           if(Text::compareIgnoreCase(name, "field"    )==0) return elem_field;
00167           return elem_nil;
00168         }
00169 
00170         vector<StackEntry> containmentStack;
00171 
00172         void warning(string message)
00173         {
00174           if(logger)
00175             logger->log(sourceName + ":" + Text::toString(XML_GetCurrentLineNumber(xmlParser)) + ": [Warning] "
00176                         + message);
00177         }
00178 
00179         Parser(Ref<ExecutionContext> context, Ref<GroupingNode> rootGroup,
00180                string sourceName, XML_Parser xmlParser,
00181                ProgressTracker *progressTracker, Logger *logger,
00182                Time creationTimeStamp, bool progressive):
00183           X3D::Parser(context, rootGroup, sourceName, logger),
00184           xmlParser(xmlParser), progressTracker(progressTracker),
00185           creationTimeStamp(creationTimeStamp), progressive(progressive)
00186         {
00187           StackEntry stackEntry;
00188           stackEntry.element = elem_toplevel;
00189           containmentStack.push_back(stackEntry);
00190           initialize();
00191         }
00192 
00193 
00197         bool isWhiteSpace(const char *s)
00198         {
00199           while(*s == ' ' || *s == '\t' || *s == '\n' ||
00200                 *s == '\r' || *s == '\f' || *s == ',') ++s;
00201           return !*s;
00202         }
00203 
00213         bool eatWord(const char *&s, const char *&from)
00214         {
00215           const char *_s = s;
00216           while(*_s == ' ' || *_s == '\t' || *_s == '\n' ||
00217                 *_s == '\r' || *_s == '\f' || *_s == ',') ++_s;
00218           if(!*_s) return false;
00219           from = _s;
00220           ++_s;
00221           while(*_s && *_s != ' ' && *_s != '\t' && *_s != '\n' &&
00222                 *_s != '\r' && *_s != '\f' && *_s != ',') ++_s;
00223           s = _s;
00224           return true;
00225         }
00226 
00227         bool eat(const char *&s, bool &v, bool &more)
00228         {
00229           try
00230           {
00231             const char *from;
00232             if(!eatWord(s, from)) return (more = false);
00233             v = ParseValues::parseBoolean(false, from, s);
00234           }
00235           catch(ParseException &e)
00236           {
00237             warning(e.getMessage() + "(assuming false)");
00238             v = false;
00239           }
00240           return true;
00241         }
00242 
00243         bool eat(const char *&s, int &v, bool &more)
00244         {
00245           try
00246           {
00247             const char *from;
00248             if(!eatWord(s, from)) return (more = false);
00249             v = ParseValues::parseInteger(true, from, s);
00250           }
00251           catch(ParseException &e)
00252           {
00253             warning(e.getMessage() + "(assuming zero)");
00254             v = 0;
00255           }
00256           return true;
00257         }
00258 
00259         bool eat(const char *&s, double &v, bool &more)
00260         {
00261           try
00262           {
00263             const char *from;
00264             if(!eatWord(s, from)) return (more = false);
00265             v = ParseValues::parseDouble(from, s);
00266           }
00267           catch(ParseException &e)
00268           {
00269             warning(e.getMessage() + "(assuming zero)");
00270             v = 0;
00271           }
00272           return true;
00273         }
00274 
00275         bool eat(const char *&s, Vector2 &v, bool &more)
00276         {
00277           try
00278           {
00279             const char *from;
00280             if(!eatWord(s, from)) return (more = false);
00281             v[0] = ParseValues::parseDouble(from, s);
00282             if(!eatWord(s, from))
00283               ARCHON_THROW1(ParseException, "2nd component missing");
00284             v[1] = ParseValues::parseDouble(from, s);
00285           }
00286           catch(ParseException &e)
00287           {
00288             warning(e.getMessage() + "(assuming zero)");
00289             v = Vector2::zero();
00290           }
00291           return true;
00292         }
00293 
00294         bool eat(const char *&s, Vector3 &v, bool &more)
00295         {
00296           try
00297           {
00298             const char *from;
00299             if(!eatWord(s, from)) return (more = false);
00300             v[0] = ParseValues::parseDouble(from, s);
00301             if(!eatWord(s, from))
00302               ARCHON_THROW1(ParseException, "2nd component missing");
00303             v[1] = ParseValues::parseDouble(from, s);
00304             if(!eatWord(s, from))
00305               ARCHON_THROW1(ParseException, "3rd component missing");
00306             v[2] = ParseValues::parseDouble(from, s);
00307           }
00308           catch(ParseException &e)
00309           {
00310             warning(e.getMessage() + "(assuming zero)");
00311             v = Vector3::zero();
00312           }
00313           return true;
00314         }
00315 
00316         bool eat(const char *&s, Vector4 &v, bool &more)
00317         {
00318           try
00319           {
00320             const char *from;
00321             if(!eatWord(s, from)) return (more = false);
00322             v[0] = ParseValues::parseDouble(from, s);
00323             if(!eatWord(s, from))
00324               ARCHON_THROW1(ParseException, "2nd component missing");
00325             v[1] = ParseValues::parseDouble(from, s);
00326             if(!eatWord(s, from))
00327               ARCHON_THROW1(ParseException, "3rd component missing");
00328             v[2] = ParseValues::parseDouble(from, s);
00329             if(!eatWord(s, from))
00330               ARCHON_THROW1(ParseException, "4th component missing");
00331             v[3] = ParseValues::parseDouble(from, s);
00332           }
00333           catch(ParseException &e)
00334           {
00335             warning(e.getMessage() + "(assuming zero)");
00336             v = Vector4::zero();
00337           }
00338           return true;
00339         }
00340 
00341         bool eat(const char *&s, Rotation3 &v, bool &more)
00342         {
00343           try
00344           {
00345             const char *from;
00346             if(!eatWord(s, from)) return (more = false);
00347             v.axis[0] = ParseValues::parseDouble(from, s);
00348             if(!eatWord(s, from))
00349               ARCHON_THROW1(ParseException, "y component missing");
00350             v.axis[1] = ParseValues::parseDouble(from, s);
00351             if(!eatWord(s, from))
00352               ARCHON_THROW1(ParseException, "z component missing");
00353             v.axis[2] = ParseValues::parseDouble(from, s);
00354             if(!eatWord(s, from))
00355               ARCHON_THROW1(ParseException, "angle missing");
00356             v.angle = ParseValues::parseDouble(from, s);
00357           }
00358           catch(ParseException &e)
00359           {
00360             warning(e.getMessage() + "(assuming no rotation)");
00361             v = Rotation3::zero();
00362           }
00363           return true;
00364         }
00365 
00366 
00370         bool eat(const char *&s, Image &v, bool &more)
00371         {
00372           try
00373           {
00374             const char *from;
00375             if(!eatWord(s, from)) return (more = false);
00376             /*
00377             v.axis[0] = ParseValues::parseDouble(from, s);
00378             if(!eatWord(s, from))
00379               ARCHON_THROW1(ParseException, "y component missing");
00380             v.axis[1] = ParseValues::parseDouble(from, s);
00381             if(!eatWord(s, from))
00382               ARCHON_THROW1(ParseException, "z component missing");
00383             v.axis[2] = ParseValues::parseDouble(from, s);
00384             if(!eatWord(s, from))
00385               ARCHON_THROW1(ParseException, "angle missing");
00386             v.angle = ParseValues::parseDouble(from, s);
00387             */
00388           }
00389           catch(ParseException &e)
00390           {
00391             warning(e.getMessage() + "(assuming no rotation)");
00392             //      v = Rotation3::zero();
00393           }
00394           return true;
00395         }
00396 
00397         bool eat(const char *&s, Time &v, bool &more)
00398         {
00399           double w;
00400           if(!eat(s, w, more)) return false;
00401           v = Time(w);
00402           return true;
00403         }
00404 
00405 
00406         template<class T>
00407         bool parseValue(const char *s, T &v)
00408         {
00409           T w;
00410           bool m;
00411           if(!eat(s, w, m))
00412           {
00413             warning("Empty string");
00414             return false;
00415           }
00416           if(!isWhiteSpace(s)) warning("Trailing garbage");
00417           v = w;
00418           return true;
00419         }
00420 
00421         template<class T>
00422         bool parseValue(const char *s, vector<T> &l)
00423         {
00424           l.clear();
00425           T v;
00426           bool m = true;
00427           while(m) if(eat(s, v, m)) l.push_back(v);
00428           return true;
00429         }
00430 
00435         bool parseValue(const char *s, string &v)
00436         {
00437           v = s;
00438           return true;
00439         }
00440 
00444         bool parseValue(const char *s, vector<string> &v)
00445         {
00446           for(;;)
00447           {
00448             while(*s == ' ' || *s == '\t' || *s == '\n' ||
00449                   *s == '\r' || *s == '\f' || *s == ',') ++s;
00450             if(!*s) break;
00451             if(*s == '"' || *s == '\'')
00452             {
00453               const char *to = strchr(s+1, *s);
00454               ++s;
00455               int n = to ? to - s : strlen(s);
00456               v.push_back(string(s, n));
00457               if(!to)
00458               {
00459                 warning("Unpaired quotation");
00460                 break;
00461               }
00462               s += n+1;
00463               continue;
00464             }
00465 
00466             const char *to = s+1;
00467             while(*to && *to != '"' && *to != '\'') ++to;
00468             --to;
00469             while(*to == ' ' || *to == '\t' || *to == '\n' ||
00470                   *to == '\r' || *to == '\f' || *to == ',') --to;
00471             ++to;
00472             int n = to - s;
00473             v.push_back(string(s, n));
00474             s = to;
00475           }
00476 
00477           return true;
00478         }
00479 
00480 
00481 
00482         struct ValueParserBase
00483         {
00484           virtual void parse(const char *, NodeBase *,
00485                              const FieldBase *, Parser *) const = 0;
00486 
00487           virtual Ref<CustomFieldBase>
00488           newCustomField(CustomFieldNode *c,
00489                          int i, string n, const FieldType *t,
00490                          bool isEventTarget, bool isEventSource,
00491                          Parser *p, const char *s) const = 0;
00492 
00493         protected:
00494           virtual ~ValueParserBase() {}
00495         };
00496 
00497         template<typename T>
00498         struct SingleValueParser: ValueParserBase
00499         {
00500           void parse(const char *s, NodeBase *n, const FieldBase *f,
00501                      Parser *p) const
00502           {
00503             T v;
00504             if(p->parseValue(s, v))
00505             {
00506               Ref<SimpleValue<T> > w = new SimpleValue<T>(f->getType(), v);
00507               Event e(w.get(), p->creationTimeStamp);
00508 
00509               /*
00510                * Note that we do not want the value assignment to
00511                * initiate an event cascade, but this is guaranteed not
00512                * to happen since this field is brand new and cannot
00513                * have any routes added to it yet. This is because we
00514                * are currently parsing the attributes of the start tag
00515                * of the node in question.
00516                */
00517               n->set(f, &e);
00518             }
00519           }
00520 
00521           Ref<CustomFieldBase>
00522           newCustomField(CustomFieldNode *c,
00523                          int i, string n, const FieldType *t,
00524                          bool isEventTarget, bool isEventSource,
00525                          Parser *p, const char *s) const
00526           {
00527             T v;
00528             if(s && p->parseValue(s, v))
00529             {
00530               return new SimpleCustomField<T>(c, i, n, t, isEventTarget,
00531                                               isEventSource, v);
00532             }
00533             return new SimpleCustomField<T>(c, i, n, t, isEventTarget,
00534                                             isEventSource, defaultValue);
00535           }
00536 
00537           SingleValueParser(const T &v): defaultValue(v) {}
00538 
00539         private:
00540           T defaultValue;
00541         };
00542 
00543         template<typename T>
00544         struct SequenceValueParser: ValueParserBase
00545         {
00546           typedef vector<T> V;
00547 
00548           void parse(const char *s, NodeBase *n, const FieldBase *f,
00549                      Parser *p) const
00550           {
00551             V v;
00552             if(p->parseValue(s, v))
00553             {
00554               Ref<SimpleValue<V> > w = new SimpleValue<V>(f->getType(), v);
00555               Event e(w.get(), p->creationTimeStamp);
00556 
00557               /*
00558                * Note that we do not want the value assignment to
00559                * initiate an event cascade, but this is guaranteed not
00560                * to happen since this field is brand new and cannot
00561                * have any routes added to it yet. This is because we
00562                * are currently parsing the attributes of the start tag
00563                * of the node in question.
00564                */
00565               n->set(f, &e);
00566             }
00567           }
00568 
00569           Ref<CustomFieldBase>
00570           newCustomField(CustomFieldNode *c,
00571                          int i, string n, const FieldType *t,
00572                          bool isEventTarget, bool isEventSource,
00573                          Parser *p, const char *s) const
00574           {
00575             V v;
00576             if(s && p->parseValue(s, v))
00577             {
00578               return new SimpleSeqCustomField<T>(c, i, n, t, isEventTarget,
00579                                                  isEventSource, v);
00580             }
00581             return new SimpleSeqCustomField<T>(c, i, n, t, isEventTarget,
00582                                                isEventSource, defaultValue);
00583           }
00584 
00585         private:
00586           V defaultValue;
00587         };
00588 
00589         map<const FieldType *, const ValueParserBase *> valueParsers;
00590 
00591         map<string, string> compatibilityFieldTypeNameMap;
00592 
00593         void initialize()
00594         {
00595           Vector4 one4;
00596           one4[0] = one4[1] = one4[2] = one4[3] = 1;
00597 
00598           valueParsers[SFBool::type]      = new SingleValueParser<bool>(false);
00599           valueParsers[MFBool::type]      = new SequenceValueParser<bool>;
00600 
00601           valueParsers[SFColor::type]     = new SingleValueParser<Vector3>(Vector3(1, 1, 1));
00602           valueParsers[MFColor::type]     = new SequenceValueParser<Vector3>;
00603 
00604           valueParsers[SFColorRGBA::type] = new SingleValueParser<Vector4>(one4);
00605           valueParsers[MFColorRGBA::type] = new SequenceValueParser<Vector4>;
00606 
00607           valueParsers[SFDouble::type]    = new SingleValueParser<double>(0);
00608           valueParsers[MFDouble::type]    = new SequenceValueParser<double>;
00609 
00610           valueParsers[SFFloat::type]     = new SingleValueParser<double>(0);
00611           valueParsers[MFFloat::type]     = new SequenceValueParser<double>;
00612 
00613           valueParsers[SFImage::type]     = new SingleValueParser<Image>(Image());
00614           valueParsers[MFImage::type]     = new SequenceValueParser<Image>;
00615 
00616           valueParsers[SFInt32::type]     = new SingleValueParser<int>(0);
00617           valueParsers[MFInt32::type]     = new SequenceValueParser<int>;
00618 
00619           valueParsers[SFRotation::type]  = new SingleValueParser<Rotation3>(Rotation3(Vector3(0, 0, 1), 0));
00620           valueParsers[MFRotation::type]  = new SequenceValueParser<Rotation3>;
00621 
00622           valueParsers[SFString::type]    = new SingleValueParser<string>(string());
00623           valueParsers[MFString::type]    = new SequenceValueParser<string>;
00624 
00625           valueParsers[SFTime::type]      = new SingleValueParser<Time>(Time());
00626           valueParsers[MFTime::type]      = new SequenceValueParser<Time>;
00627 
00628           valueParsers[SFVec2d::type]     = new SingleValueParser<Vector2>(Vector2(0, 0));
00629           valueParsers[MFVec2d::type]     = new SequenceValueParser<Vector2>;
00630 
00631           valueParsers[SFVec2f::type]     = new SingleValueParser<Vector2>(Vector2(0, 0));
00632           valueParsers[MFVec2f::type]     = new SequenceValueParser<Vector2>;
00633 
00634           valueParsers[SFVec3d::type]     = new SingleValueParser<Vector3>(Vector3(0, 0, 0));
00635           valueParsers[MFVec3d::type]     = new SequenceValueParser<Vector3>;
00636 
00637           valueParsers[SFVec3f::type]     = new SingleValueParser<Vector3>(Vector3(0, 0, 0));
00638           valueParsers[MFVec3f::type]     = new SequenceValueParser<Vector3>;
00639 
00640 
00641           compatibilityFieldTypeNameMap["Boolean"]            = "SFBool";
00642           compatibilityFieldTypeNameMap["Booleans"]           = "MFBool";
00643           compatibilityFieldTypeNameMap["Color"]              = "SFColor";
00644           compatibilityFieldTypeNameMap["Colors"]             = "MFColor";
00645           compatibilityFieldTypeNameMap["Double"]             = "SFDouble";
00646           compatibilityFieldTypeNameMap["Doubles"]            = "MFDouble";
00647           compatibilityFieldTypeNameMap["Float"]              = "SFFloat";
00648           compatibilityFieldTypeNameMap["Floats"]             = "MFFloat";
00649           compatibilityFieldTypeNameMap["Image"]              = "SFImage";
00650           compatibilityFieldTypeNameMap["Images"]             = "MFImage";
00651           compatibilityFieldTypeNameMap["Integer"]            = "SFInt32";
00652           compatibilityFieldTypeNameMap["Integers"]           = "MFInt32";
00653           compatibilityFieldTypeNameMap["Node"]               = "SFNode";
00654           compatibilityFieldTypeNameMap["Nodes"]              = "MFNode";
00655           compatibilityFieldTypeNameMap["Rotation"]           = "SFRotation";
00656           compatibilityFieldTypeNameMap["Rotations"]          = "MFRotation";
00657           compatibilityFieldTypeNameMap["String"]             = "SFString";
00658           compatibilityFieldTypeNameMap["Strings"]            = "MFString";
00659           compatibilityFieldTypeNameMap["Time"]               = "SFTime";
00660           compatibilityFieldTypeNameMap["Times"]              = "MFTime";
00661           compatibilityFieldTypeNameMap["Vector2Float"]       = "SFVec2f";
00662           compatibilityFieldTypeNameMap["Vector2FloatArray"]  = "MFVec2f";
00663           compatibilityFieldTypeNameMap["Vector3Float"]       = "SFVec3f";
00664           compatibilityFieldTypeNameMap["Vector3FloatArray"]  = "MFVec3f";
00665           compatibilityFieldTypeNameMap["Vector2Double"]      = "SFVec2f";
00666           compatibilityFieldTypeNameMap["Vector2DoubleArray"] = "MFVec2f";
00667           compatibilityFieldTypeNameMap["Vector3Double"]      = "SFVec3d";
00668           compatibilityFieldTypeNameMap["Vector3DoubleArray"] = "MFVec3d";
00669         }
00670 
00671         Ref<NodeBase> lookupUseNode(string name, const NodeType *type)
00672         {
00673           Ref<NodeBase> node = lookupNode(name);
00674           if(!node)
00675           {
00676             warning("Undefined name '" + name + "' in 'USE'");
00677             return 0;
00678           }
00679           if(node->getType() != type)
00680           {
00681             warning("Attempt to use '" + node->getType()->getName() + "' as '" + type->getName() + "'");
00682             return 0;
00683           }
00684           return node;
00685         }
00686 
00687         Ref<NodeBase> checkUseAttribute(const char *atts[], const NodeType *nodeType)
00688         {
00689           Ref<NodeBase> n;
00690           bool noUse = false;
00691           for(int i=0; atts[i] && atts[i+1]; i+=2)
00692           {
00693             if(Text::compareIgnoreCase(atts[i], "USE") == 0)
00694             {
00695               if(string(atts[i]) != "USE")
00696                 warning("Attribute '" + string(atts[i]) + "' should be spelled 'USE'");
00697               n = lookupUseNode(atts[i+1], nodeType);
00698             }
00699             else if(Text::compareIgnoreCase(atts[i], "containerField") != 0)
00700               noUse = true;
00701             if(noUse && n)
00702             {
00703               warning("Only the 'containerField' attributes is accepted in conjunction with 'USE'");
00704               break;
00705             }
00706           }
00707           return n;
00708         }
00709 
00710         void displayStack(bool push)
00711         {
00712           vector<double> columnWidthFractions;
00713           columnWidthFractions.push_back(2);
00714           columnWidthFractions.push_back(5);
00715           columnWidthFractions.push_back(10);
00716           columnWidthFractions.push_back(10);
00717           columnWidthFractions.push_back(2);
00718           columnWidthFractions.push_back(2);
00719           columnWidthFractions.push_back(10);
00720           columnWidthFractions.push_back(10);
00721           Text::Table<string> table(containmentStack.size()+1, columnWidthFractions);
00722           for(unsigned i=0; i<containmentStack.size(); ++i)
00723           {
00724             StackEntry &e = containmentStack[i];
00725             table(i, 0) = Text::toString(i);
00726             table(i, 1) = getElementName(e.element);
00727             table(i, 2) = e.node ? e.node->getType()->getName() : "";
00728             table(i, 3) = e.node ? e.node->getName() : "";
00729             table(i, 4) = "->";
00730             table(i, 5) = Text::toString(e.containerStackIndex);
00731             table(i, 6) = e.containerField ? e.containerField->getName() : "";
00732             table(i, 7) = e.containerField ? e.containerField->getType()->getName() : "";
00733           }
00734 
00735           logger->log("Stack " + string(push?"push":"pop") + ":\n" +
00736                       Text::format(table, Term::getWidth(), 2, false));
00737         }
00738 
00739         bool attr_cmp(string s, string attribute, Element element,
00740                       bool deprecated = false)
00741         {
00742           if(Text::compareIgnoreCase(s, attribute)==0)
00743           {
00744             if(s != attribute)
00745               warning("Attribute '" + s + "' of element '" +
00746                       getElementName(element) + "' should be spelled '" +
00747                       attribute + "'");
00748             if(deprecated)
00749               warning("Use of attribute '" + s + "' in element '" +
00750                       getElementName(element) + "' is deprecated.");
00751             return true;
00752           }
00753           return false;
00754         }
00755 
00756         /*
00757          * Rules for verification of element containment:
00758          *
00759          * The X3D element may be contained in the imaginary top-level
00760          * element only.
00761          *
00762          * The special non-node hierachical elements such as head, meta,
00763          * component & Scene may never be contained in any node-type
00764          * element.
00765          *
00766          * Route and Proto elements may be contained in the scene element
00767          * or in any element contained directly or indirectly in the scene
00768          * element.
00769          *
00770          * Node-type elements may be contained in other node-type elements
00771          * according to their runtime type information only with the
00772          * exception that those derived from the ChildNode may be
00773          * contained in the special Scene element.
00774          *
00775          * Nothing may be contained in a node-type element that utilizes
00776          * the USE attribute.
00777          *
00778          * When verifying the containment rules, the containment stack is
00779          * consulted. The element at the top of the stack is always the
00780          * element that imediately encloses the currently encountered
00781          * element. If this element at the top of the stack is a valid
00782          * container for the new element, then all is fine. If not, then
00783          * the stack is traversed from top to bottom, to see if any
00784          * non-immediately enclosing element complies as a container. If
00785          * such a container is found then it will be used but a warning
00786          * will be issued.
00787          *
00788          * Any encountered element that does not have a compliant
00789          * container on the stack will be ignored
00790          */
00791         void parseStartElement(const char *name, const char *atts[],
00792                                StackEntry *stackEntry)
00793         {
00794           // Determine the type of element
00795           Element element = elementLookup(name);
00796           const NodeType *nodeType = 0;
00797 
00798           if(element == elem_nil)
00799           {
00800             nodeType = NodeType::lookup(name);
00801 
00802             if(!nodeType || !nodeType->isUserInstantiable())
00803             {
00804               warning("Unknown element '" + string(name) + "' (element ignored)");
00805               return;
00806             }
00807 
00808             if(nodeType->getName() != name)
00809               warning("Element '" + string(name) + "' should be spelled '" +
00810                       nodeType->getName() + "'");
00811 
00812             element = elem_node; // May later become 'elem_use'
00813           }
00814           else if(getElementName(element) != name)
00815             warning("Element '" + string(name) + "' should be spelled '" +
00816                     getElementName(element) + "'");
00817 
00818 
00819           // For elements of node type determine the desired name of
00820           // the container field
00821           string containerFieldName;
00822           if(nodeType)
00823           {
00824             bool found = false;
00825             for(int i=0; atts[i] && atts[i+1]; i+=2)
00826             {
00827               if(Text::compareIgnoreCase(atts[i], "containerField") == 0)
00828               {
00829                 if(string(atts[i]) != "containerField")
00830                   warning("Attribute '" + string(atts[i]) + "' should be spelled 'containerField'");
00831                 containerFieldName = atts[i+1];
00832                 found = true;
00833                 break;
00834               }
00835             }
00836             if(!found) containerFieldName = nodeType->getContainerField();
00837           }
00838 
00839           /*
00840            * Find the container element (and the target field for
00841            * node-type elements):
00842            *
00843            * See the note on containment verification rules above!
00844            *
00845            * When the search terminates 'containerStackIndex == -1'
00846            * indicates 'not found', else if 'containerField == 0' the the
00847            * new element is a child of the Scene element.
00848            */
00849           int containerStackIndex = -1;
00850           const NodeFieldBase *containerField = 0;
00851           bool fallThrough = false;
00852           for(int i = int(containmentStack.size())-1; i>=0; --i)
00853           {
00854             if(i < int(containmentStack.size())-1) fallThrough = true;
00855 
00856             Element containerElement = containmentStack[i].element;
00857 
00858             // Get rid of impossible containers
00859             if(containerElement == elem_nil ||
00860                containerElement == elem_route ||
00861                containerElement == elem_proto ||
00862                containerElement == elem_use) continue;
00863 
00864             // Handle new node-type elements
00865             if(element == elem_node)
00866             {
00867               if(containerElement == elem_field)
00868               {
00869                 if(NodeFieldBase *f = dynamic_cast<NodeFieldBase *>(containmentStack[i].field.get()))
00870                 {
00871                   containerStackIndex = containmentStack[i].containerStackIndex;
00872                   containerField = f;
00873                   break;
00874                 }
00875                 continue;
00876               }
00877 
00878               if(containerElement == elem_scene &&
00879                  nodeType->isDerivedFrom(ChildNode::type))
00880               {
00881                 containerStackIndex = i;
00882                 break;
00883               }
00884 
00885               if(containerElement != elem_node) break;
00886 
00887               Ref<NodeBase> n = containmentStack[i].node;
00888               if(!n) ARCHON_THROW1(InternalException,
00889                                    "x3d/parse_xml: Stack entry "
00890                                    "unexpectedly had no node");
00891               const NodeType *t = n->getType();
00892               containerField = dynamic_cast<const NodeFieldBase *>(t->lookupField(containerFieldName));
00893               if(!containerField)
00894               {
00895                 containerField = t->lookupNodeField(nodeType);
00896                 if(containerField)
00897                   warning("Bad container field '" + containerFieldName +
00898                           "' (using '" + containerField->getName() + "')");
00899               }
00900               if(containerField)
00901               {
00902                 containerStackIndex = i;
00903                 break;
00904               }
00905               continue;
00906             }
00907 
00908             // Handle Script fields
00909             if(element == elem_field)
00910             {
00911               if(containerElement != elem_node) continue;
00912 
00913               Ref<NodeBase> n = containmentStack[i].node;
00914               if(!n) ARCHON_THROW1(InternalException,
00915                                    "XML::Parser::parseStartElement: "
00916                                    "Stack entry unexpectedly had no "
00917                                    "node");
00918               if(!dynamic_cast<CustomFieldNode *>(n.get())) continue;
00919               containerStackIndex = i;
00920               break;
00921             }
00922 
00923             // Handle Route and PROTO
00924             if(element == elem_route || element == elem_proto)
00925             {
00926               if(containerElement == elem_scene ||
00927                  containerElement == elem_node)
00928               {
00929                 containerStackIndex = i;
00930                 break;
00931               }
00932               continue;
00933             }
00934 
00935             // Handle special non-node hierachical elements
00936             if(element == elem_x3d && containerElement == elem_toplevel ||
00937                element == elem_head && containerElement == elem_x3d ||
00938                element == elem_meta && containerElement == elem_head ||
00939                element == elem_component && containerElement == elem_head ||
00940                element == elem_scene && containerElement == elem_x3d)
00941             {
00942               containerStackIndex = i;
00943               break;
00944             }
00945           }
00946 
00947 
00948           /*
00949            * If we didn't find a compatible container element or
00950            * the container element wasn't the imediately enclosing element
00951            *
00952            * Note: this should be converted to a switch statement!
00953            */
00954           if(containerStackIndex < 0 || fallThrough)
00955           {
00956             string message;
00957             switch(containmentStack.back().element)
00958             {
00959             case elem_toplevel:
00960               message = "Element '" + getElementName(element, nodeType) +
00961                 "' is not allowed as the top level element";
00962               break;
00963             case elem_use:
00964               message = "Element '" + getElementName(element, nodeType) +
00965                 "' is not allowed in elements that employ the USE "
00966                 "attribute";
00967               break;
00968             case elem_nil:
00969               message = "Ill placed element '" +
00970                 getElementName(element, nodeType) + "'";
00971               break;
00972             case elem_field:
00973               message = "Node elements are not allowed in field elements "
00974                 "of type '" +
00975                 containmentStack.back().field->getType()->getName() + "'";
00976               break;
00977             default:
00978               message = "Element '" + getElementName(element, nodeType) +
00979                 "' is not allowed in '" +
00980                 getElementName(containmentStack.back()) + "'";
00981             }
00982 
00983             if(containerStackIndex == -1)
00984             {
00985               warning(message + " (element ignored)");
00986               return;
00987             }
00988 
00989             warning(message + " (fall-through to closest '" +
00990                     getElementName(containmentStack[containerStackIndex]) +
00991                     "' established)");
00992           }
00993 
00994 
00995           Ref<NodeBase> node;
00996           Ref<CustomFieldBase> field;
00997 
00998           if(element == elem_route)
00999           {
01000             string fromNode;
01001             string fromField;
01002             string toNode;
01003             string toField;
01004             bool gotFromNode  = false;
01005             bool gotFromField = false;
01006             bool gotToNode    = false;
01007             bool gotToField   = false;
01008           
01009             for(int i=0; atts[i] && atts[i+1]; i+=2)
01010             {
01011               if(attr_cmp(atts[i], "fromNode", element))
01012               {
01013                 gotFromNode = parseValue(atts[i+1], fromNode);
01014               }
01015               else if(attr_cmp(atts[i], "fromField", element))
01016               {
01017                 gotFromField = parseValue(atts[i+1], fromField);
01018               }
01019               else if(attr_cmp(atts[i], "toNode", element))
01020               {
01021                 gotToNode = parseValue(atts[i+1], toNode);
01022               }
01023               else if(attr_cmp(atts[i], "toField", element))
01024               {
01025                 gotToField = parseValue(atts[i+1], toField);
01026               }
01027               else
01028               {
01029                 warning("Unrecognized attribute '" + string(atts[i]) +
01030                         "' of element '" + getElementName(element) + "' (attribute ignored)");
01031               }
01032             }
01033 
01034             bool skip = false;
01035             if(!gotFromNode)
01036             {
01037               warning("Required attribute 'fromNode' of element '" +
01038                       getElementName(element) + "' is missing (element ignored)");
01039               skip = true;
01040             }
01041             if(!gotFromField)
01042             {
01043               warning("Required attribute 'fromField' of element '" +
01044                       getElementName(element) + "' is missing (element ignored)");
01045               skip = true;
01046             }
01047             if(!gotToNode)
01048             {
01049               warning("Required attribute 'toNode' of element '" +
01050                       getElementName(element) + "' is missing (element ignored)");
01051               skip = true;
01052             }
01053             if(!gotToField)
01054             {
01055               warning("Required attribute 'toField' of element '" +
01056                       getElementName(element) + "' is missing (element ignored)");
01057               skip = true;
01058             }
01059             if(!skip) addRoute(fromNode, fromField, toNode, toField);
01060           }
01061           else if(element == elem_proto)
01062           {
01063             warning("Element '" + getElementName(element) + "' is not supported yet (ignored)");
01064           }
01065           else if(element == elem_field)
01066           {
01067             string name;
01068             string accessType;
01069             string type;
01070             string use;
01071 
01072             bool gotName       = false;
01073             bool gotAccessType = false;
01074             bool gotType       = false;
01075             int  gotValue      = -1; // If >= 0 value is atts[gotValue]
01076             bool gotUse        = false;
01077           
01078             for(int i=0; atts[i] && atts[i+1]; i+=2)
01079             {
01080               if(attr_cmp(atts[i], "name", element))
01081               {
01082                 gotName = parseValue(atts[i+1], name);
01083               }
01084               else if(attr_cmp(atts[i], "accessType", element))
01085               {
01086                 gotAccessType = parseValue(atts[i+1], accessType);
01087               }
01088               else if(attr_cmp(atts[i], "type", element))
01089               {
01090                 gotType = parseValue(atts[i+1], type);
01091               }
01092               else if(attr_cmp(atts[i], "value", element))
01093               {
01094                 gotValue = i+1;
01095               }
01096               else if(attr_cmp(atts[i], "USE", element, true))
01097               {
01098                 // This attribute is deprecated
01099                 gotUse = parseValue(atts[i+1], use);
01100               }
01101               else
01102               {
01103                 warning("Unrecognized attribute '" + string(atts[i]) +
01104                         "' of element '" + getElementName(element) + "' (attribute ignored)");
01105               }
01106             }
01107 
01108             bool isEventTarget = false;
01109             bool isEventSource = false;
01110 
01111             bool skip = false;
01112             if(gotName && !validateIdentifier(name))
01113             {
01114               warning("Illegal value '" + name + "' of attribute 'name' "
01115                       "in element 'field' (element ignored)");
01116               skip = true;            
01117             }
01118 
01119             if(gotAccessType)
01120             {
01121               if(Text::compareIgnoreCase("initializeOnly", accessType) == 0 ||
01122                  Text::compareIgnoreCase("field", accessType) == 0);
01123               else if(Text::compareIgnoreCase("inputOnly", accessType) == 0 ||
01124                       Text::compareIgnoreCase("eventIn", accessType) == 0)
01125                 isEventTarget = true;
01126               else if(Text::compareIgnoreCase("outputOnly", accessType) == 0 ||
01127                       Text::compareIgnoreCase("eventOut", accessType) == 0)
01128                 isEventSource = true;
01129               else if(Text::compareIgnoreCase("inputOutput", accessType) == 0 ||
01130                       Text::compareIgnoreCase("exposedField", accessType) == 0)
01131                 isEventTarget = isEventSource = true;
01132               else
01133               {
01134                 warning("Unrecognized attribute value '" + accessType +
01135                         "' of attribute 'accessType' of element 'field' "
01136                         "(assuming 'initializeOnly')");
01137                 accessType = "initializeOnly";
01138               }
01139 
01140               if(!isEventTarget && !isEventSource &&
01141                  accessType != "initializeOnly")
01142                 warning("Attribute value '" + accessType + "' of attribute "
01143                         "'accessType' of element 'field' should be spelled "
01144                         "'initializeOnly'");
01145               if(isEventTarget && !isEventSource && accessType != "inputOnly")
01146                 warning("Attribute value '" + accessType + "' of attribute "
01147                         "'accessType' of element 'field' should be spelled "
01148                         "'inputOnly'");
01149               if(!isEventTarget && isEventSource && accessType != "outputOnly")
01150                 warning("Attribute value '" + accessType + "' of attribute "
01151                         "'accessType' of element 'field' should be spelled "
01152                         "'outputOnly'");
01153               if(isEventTarget && isEventSource && accessType != "inputOutput")
01154                 warning("Attribute value '" + accessType + "' of attribute "
01155                         "'accessType' of element 'field' should be spelled "
01156                         "'inputOutput'");
01157             }
01158 
01159             const FieldType *fieldType = 0;
01160             if(gotType)
01161             {
01162               string mappedType = type;
01163               map<string, string>::iterator i =
01164                 compatibilityFieldTypeNameMap.find(type);
01165               if(i != compatibilityFieldTypeNameMap.end())
01166                 mappedType = i->second;
01167 
01168               fieldType = FieldType::lookup(mappedType);
01169               if(!fieldType)
01170               {
01171                 warning("Unrecognized attribute value '" + type + "' of attribute "
01172                         "'type' of element 'field' (element ignored)");
01173                 skip = true;
01174               }
01175               else if(fieldType->getName() != type)
01176                 warning("Attribute value '" + type + "' of attribute "
01177                         "'type' of element 'field' should be spelled "
01178                         "'" + fieldType->getName() + "'");
01179             }
01180 
01181             if(!gotName)
01182             {
01183               warning("Required attribute 'Name' of element '" +
01184                       getElementName(element) + "' is missing (element ignored)");
01185               skip = true;
01186             }
01187             if(!gotAccessType)
01188               warning("Required attribute 'accessType' of element '" +
01189                       getElementName(element) + "' is missing (assuming 'initializeOnly')");
01190             if(!gotType)
01191             {
01192               warning("Required attribute 'type' of element '" +
01193                       getElementName(element) + "' is missing (element ignored)");
01194               skip = true;
01195             }
01196 
01197             // Instantiate a field object for the element stack
01198             if(!skip && fieldType)
01199             {
01200               CustomFieldNode *n = dynamic_cast<CustomFieldNode *>
01201                 (containmentStack[containerStackIndex].node.get());
01202               if(!n) ARCHON_THROW1(InternalException,
01203                                    "XML::Parser::parseStartElement: "
01204                                    "Custom field container was not a "
01205                                    "CustumFieldNode");
01206               int customFieldIndex = getNextCustomFieldIndex(n);
01207 
01208               Ref<Node> useNode;
01209               if(gotUse)
01210               {
01211                 Ref<NodeBase> u = lookupNode(use);
01212                 useNode = dynamic_cast<Node *>(u.get());
01213                 if(!useNode)
01214                   warning("Undefined node name '" + use + "' in 'USE' "
01215                           "attribute of field element");
01216               }
01217 
01218               if(fieldType == SFNode::type)
01219                 field = new NodeCustomField<Node>
01220                   (n, customFieldIndex, name, Node::type,
01221                    isEventTarget, isEventSource, useNode);
01222               else if(fieldType == MFNode::type)
01223               {
01224                 vector<Ref<Node> > v;
01225                 if(useNode) v.push_back(useNode);
01226                 field = new NodeSequenceCustomField<Node>
01227                   (n, customFieldIndex, name, Node::type,
01228                    isEventTarget, isEventSource, v);
01229               }
01230               else
01231               {
01232                 field = valueParsers[fieldType]->newCustomField
01233                   (n, customFieldIndex, name, fieldType,
01234                    isEventTarget, isEventSource,
01235                    this, gotValue >= 0 ? atts[gotValue] : 0);
01236                 if(useNode)
01237                   warning("The USE attribute may not be used in field "
01238                           "elements with type '" + fieldType->getName() +
01239                           "' (attribute ignored)");
01240               }
01241             }
01242           }
01243           else if(element == elem_node)
01244           {
01245             // Is it a "reuse" element refering to an already instantiated named node?
01246             node = checkUseAttribute(atts, nodeType);
01247 
01248 
01249             /*
01250              * Instantiate a node of the desired type if it wasn't a
01251              * "reuse" element.
01252              */
01253             if(node) element = elem_use;
01254             else node = nodeType->instantiate(context);
01255 
01256 
01257             // Parse attributes
01258             if(element != elem_use) for(int i=0; atts[i] && atts[i+1]; i+=2)
01259             {
01260               if(Text::compareIgnoreCase(atts[i], "DEF") == 0)
01261               {
01262                 if(string(atts[i]) != "DEF")
01263                   warning("Attribute '" + string(atts[i]) + "' should be spelled 'DEF'");
01264 
01265                 const string name = atts[i+1];
01266                 if(validateIdentifier(name)) addNamedNode(name, node);
01267                 else
01268                   warning("Illegal value '" + name + "' of attribute 'DEF' "
01269                           "in element '" + nodeType->getName() + "' (attribute ignored)");
01270               }
01271               else if(Text::compareIgnoreCase(atts[i], "containerField") != 0)
01272               {
01273                 const FieldBase *field = nodeType->lookupField(atts[i]);
01274                 if(!field)
01275                 {
01276                   warning("Unrecognized attribute '" + string(atts[i]) +
01277                           "' of element '" + nodeType->getName() + "' (attribute ignored)");
01278                   continue;
01279                 }
01280                 if(field->getType() == SFNode::type || field->getType() == MFNode::type)
01281                 {
01282                   warning("Illegal node type attribute '" + string(atts[i]) +
01283                           "' of element '" + nodeType->getName() + "' (attribute ignored)");
01284                   continue;
01285                 }
01286 
01287                 if(field->getName() != atts[i])
01288                   warning("Attribute '" + string(atts[i]) + "' should be spelled '" +
01289                           field->getName() + "'");
01290 
01291                 valueParsers[field->getType()]->parse(atts[i+1], node.get(), field, this);
01292               }
01293             }
01294           }
01295 
01296           stackEntry->element = element;
01297           stackEntry->node = node;
01298           stackEntry->field = field;
01299           stackEntry->containerField = containerField;
01300           stackEntry->containerStackIndex = containerStackIndex;
01301 
01302           if(progressive &&
01303              (element == elem_node || element == elem_use) &&
01304              !dynamic_cast<CustomFieldNode *>(node.get()))
01305             injectChild(stackEntry);
01306         }
01307 
01308         void startElement(const char *name, const char *atts[])
01309         {
01310           StackEntry stackEntry;
01311           parseStartElement(name, atts, &stackEntry);
01312           containmentStack.push_back(stackEntry);
01313           //displayStack(true);
01314         }
01315 
01316         void endElement()
01317         {
01318           StackEntry stackEntry = containmentStack.back();
01319           containmentStack.pop_back();
01320           //displayStack(false);
01321 
01322           // Is it a field element?
01323           if(stackEntry.element == elem_field)
01324           {
01325             if(!stackEntry.field) return;
01326             if(stackEntry.containerStackIndex < 0) return;
01327             Ref<CustomFieldNode> n = dynamic_cast<CustomFieldNode *>
01328               (containmentStack[stackEntry.containerStackIndex].node.get());
01329             if(!n) ARCHON_THROW1(InternalException,
01330                                  "XML::Parser::endElement: "
01331                                  "Custom field container was not a "
01332                                  "CustomFieldNode");
01333 
01334             addScriptField(n, stackEntry.field);
01335 
01336             return;
01337           }
01338 
01339           // Skip all non-node elements
01340           if(stackEntry.element != elem_node &&
01341              stackEntry.element != elem_use) return;
01342 
01343           // Inject XML/CDATA into CDATA nodes
01344           if(stackEntry.element == elem_node)
01345             if(CDATANode *n = dynamic_cast<CDATANode *>(stackEntry.node.get()))
01346             {
01347               string s = Text::trim(stackEntry.cdata);
01348               if(s.size()) n->handleCDATA(s, creationTimeStamp);
01349             }
01350 
01351           if(!progressive ||
01352              dynamic_cast<CustomFieldNode *>(stackEntry.node.get()))
01353             injectChild(&stackEntry);
01354         }
01355 
01356         void injectChild(StackEntry *stackEntry)
01357         {
01358           // Is it a Scene child?
01359           if(!stackEntry->containerField)
01360           {
01361             addRootGroupChild(dynamic_cast<ChildNode *>
01362                               (stackEntry->node.get()), creationTimeStamp);
01363             return;
01364           }
01365 
01366           // Is there room for another node in the target field? Try
01367           // to inject it!
01368           if(!containmentStack[stackEntry->containerStackIndex].node->inject
01369                (stackEntry->containerField, stackEntry->node, creationTimeStamp))
01370             warning("Element '" +
01371                     containmentStack[stackEntry->containerStackIndex].node->
01372                     getType()->getName() +
01373                     "' already contains a '" +
01374                     stackEntry->node->getType()->getName() +
01375                     "' (additional element ignored)");
01376         }
01377 
01378         void characterDataHandler(const char *s, int n)
01379         {
01380           StackEntry &stackEntry = containmentStack.back();
01381           if(dynamic_cast<const CDATANode *>(stackEntry.node.get()))
01382             stackEntry.cdata.append(s, n);
01383         }
01384       };
01385 
01386       namespace
01387       {
01388         void startElement(void *userData, const char *name, const char *atts[]) throw()
01389         {
01390           Parser *p = static_cast<Parser *>(userData);
01391           p->startElement(name, atts);
01392         }
01393 
01394         void endElement(void *userData, const char *) throw()
01395         {
01396           Parser *p = static_cast<Parser *>(userData);
01397           p->endElement();
01398         }
01399 
01400         void characterData(void *userData, const char *s, int n)
01401         {
01402           Parser *p = static_cast<Parser *>(userData);
01403           p->characterDataHandler(s, n);
01404         }
01405 
01406         struct XmlParserWrapper
01407         {
01408           const XML_Parser ptr;
01409 
01410           XmlParserWrapper(XML_Parser ptr):ptr(ptr) {}
01411 
01412           ~XmlParserWrapper()
01413           {{ // The extra scope is needed to work around gcc3.2 bug #8287
01414             if(ptr) XML_ParserFree(ptr);
01415           }}
01416         };
01417       }
01418 
01419 
01420       void parse(Ref<ExecutionContext> context, Ref<GroupingNode> group,
01421                  Ref<Stream::Reader> reader, bool progressive, Logger *logger,
01422                  string sourceName, ProgressTracker *progressTracker)
01423       {
01424         Ref<Server> server;
01425         try { server = context->server.getRef(); }
01426         catch(ForwardDestroyedException &) { return; }
01427 
01428         XmlParserWrapper p(XML_ParserCreate(0));
01429         XML_SetElementHandler(p.ptr, startElement, endElement);
01430         XML_SetCharacterDataHandler(p.ptr, characterData);
01431 
01432         Parser parser(context, group,
01433                       sourceName.empty() ? context->getBaseUri().getFile() :
01434                       sourceName, p.ptr, progressTracker,
01435                       logger ? logger : server->getLogger(),
01436                       server->getNextTimeStamp(), progressive);
01437         XML_SetUserData(p.ptr, &parser);
01438 
01439         const unsigned bufferSize = 1024;
01440         char buffer[bufferSize];
01441 
01442         int progress = 0;
01443         for(;;)
01444         {
01445           const int n = reader->read(buffer, bufferSize);
01446           if(!XML_Parse(p.ptr, buffer, n, n==0))
01447             ARCHON_THROW1(ParseException, XML_ErrorString(XML_GetErrorCode(p.ptr)));
01448           if(n==0) break;
01449           progress += n;
01450           if(progressTracker) progressTracker->progress(progress);
01451         }
01452       }
01453     }
01454   }
01455 }

Generated on Sun Jul 30 22:55:50 2006 for Archon by  doxygen 1.4.4