DDXParser.cc

Go to the documentation of this file.
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2003 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 #include "config.h"
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <stdarg.h>
00031 
00032 #include "BaseType.h"
00033 #include "Constructor.h"
00034 #include "DDXParser.h"
00035 
00036 #include "util.h"
00037 #include "debug.h"
00038 
00039 static const not_used char *states[] =
00040     {
00041         "start",
00042 
00043         "dataset",
00044 
00045         "attribute_container",
00046         "attribute",
00047         "attribute_value",
00048 
00049         "alias",
00050 
00051         "simple_type",
00052 
00053         "array",
00054         "dimension",
00055 
00056         "grid",
00057         "map",
00058 
00059         "structure",
00060         "sequence",
00061 
00062         "blob href",
00063 
00064         "unknown",
00065         "error"
00066     };
00067 
00068 // Glue the BaseTypeFactory to the enum-based factory defined statically
00069 // here.
00070 BaseType *DDXParser::factory(Type t, const string & name)
00071 {
00072     switch (t) {
00073     case dods_byte_c:
00074         return d_factory->NewByte(name);
00075         break;
00076 
00077     case dods_int16_c:
00078         return d_factory->NewInt16(name);
00079         break;
00080 
00081     case dods_uint16_c:
00082         return d_factory->NewUInt16(name);
00083         break;
00084 
00085     case dods_int32_c:
00086         return d_factory->NewInt32(name);
00087         break;
00088 
00089     case dods_uint32_c:
00090         return d_factory->NewUInt32(name);
00091         break;
00092 
00093     case dods_float32_c:
00094         return d_factory->NewFloat32(name);
00095         break;
00096 
00097     case dods_float64_c:
00098         return d_factory->NewFloat64(name);
00099         break;
00100 
00101     case dods_str_c:
00102         return d_factory->NewStr(name);
00103         break;
00104 
00105     case dods_url_c:
00106         return d_factory->NewUrl(name);
00107         break;
00108 
00109     case dods_array_c:
00110         return d_factory->NewArray(name);
00111         break;
00112 
00113     case dods_structure_c:
00114         return d_factory->NewStructure(name);
00115         break;
00116 
00117     case dods_sequence_c:
00118         return d_factory->NewSequence(name);
00119         break;
00120 
00121     case dods_grid_c:
00122         return d_factory->NewGrid(name);
00123         break;
00124 
00125     default:
00126         return 0;
00127     }
00128 }
00129 
00131 static Type get_type(const char *name)
00132 {
00133     if (strcmp(name, "Byte") == 0)
00134         return dods_byte_c;
00135 
00136     if (strcmp(name, "Int16") == 0)
00137         return dods_int16_c;
00138 
00139     if (strcmp(name, "UInt16") == 0)
00140         return dods_uint16_c;
00141 
00142     if (strcmp(name, "Int32") == 0)
00143         return dods_int32_c;
00144 
00145     if (strcmp(name, "UInt32") == 0)
00146         return dods_uint32_c;
00147 
00148     if (strcmp(name, "Float32") == 0)
00149         return dods_float32_c;
00150 
00151     if (strcmp(name, "Float64") == 0)
00152         return dods_float64_c;
00153 
00154     if (strcmp(name, "String") == 0)
00155         return dods_str_c;
00156 
00157     if (strcmp(name, "Url") == 0)
00158         return dods_url_c;
00159 
00160     if (strcmp(name, "Array") == 0)
00161         return dods_array_c;
00162 
00163     if (strcmp(name, "Structure") == 0)
00164         return dods_structure_c;
00165 
00166     if (strcmp(name, "Sequence") == 0)
00167         return dods_sequence_c;
00168 
00169     if (strcmp(name, "Grid") == 0)
00170         return dods_grid_c;
00171 
00172     return dods_null_c;
00173 }
00174 
00175 static Type is_simple_type(const char *name)
00176 {
00177     Type t = get_type(name);
00178     switch (t) {
00179     case dods_byte_c:
00180     case dods_int16_c:
00181     case dods_uint16_c:
00182     case dods_int32_c:
00183     case dods_uint32_c:
00184     case dods_float32_c:
00185     case dods_float64_c:
00186     case dods_str_c:
00187     case dods_url_c:
00188         return t;
00189     default:
00190         return dods_null_c;
00191     }
00192 }
00193 
00194 static bool is_not(const char *name, const char *tag)
00195 {
00196     return strcmp(name, tag) != 0;
00197 }
00198 
00199 void DDXParser::set_state(DDXParser::ParseState state)
00200 {
00201     s.push(state);
00202 }
00203 
00204 DDXParser::ParseState DDXParser::get_state() const
00205 {
00206     return s.top();
00207 }
00208 
00209 void DDXParser::pop_state()
00210 {
00211     s.pop();
00212 }
00213 
00217 void DDXParser::transfer_attrs(const char **attrs)
00218 {
00219     attributes.clear();         // erase old attributes
00220 
00221     if (!attrs)
00222         return;
00223 
00224     for (int i = 0; attrs[i] != 0; i += 2) {
00225         string attr_i = attrs[i];
00226         downcase(attr_i);
00227         attributes[attr_i] = string(attrs[i + 1]);
00228     }
00229 }
00230 
00235 bool DDXParser::check_required_attribute(const string & attr)
00236 {
00237     bool found = false;
00238     map < string, string >::iterator i;
00239     for (i = attributes.begin(); i != attributes.end(); ++i)
00240         if (i->first == attr)
00241             found = true;
00242 
00243     if (!found)
00244         ddx_fatal_error(this, "Required attribute '%s' not found.",
00245                         attr.c_str());
00246 
00247     return found;
00248 }
00249 
00255 void DDXParser::process_attribute_element(const char **attrs)
00256 {
00257     // These methods set the state to parser_error if a problem is found.
00258     transfer_attrs(attrs);
00259     bool error = !(check_required_attribute(string("name"))
00260                    && check_required_attribute(string("type")));
00261     if (error)
00262         return;
00263 
00264     if (attributes["type"] == "Container") {
00265         set_state(inside_attribute_container);
00266 
00267         AttrTable *child;
00268         AttrTable *parent = at_stack.top();
00269 
00270         child = parent->append_container(attributes["name"]);
00271         at_stack.push(child);   // save.
00272         DBG2(cerr << "Pushing at" << endl);
00273     }
00274     else {
00275         set_state(inside_attribute);
00276 
00277         dods_attr_name = attributes["name"];
00278         dods_attr_type = attributes["type"];
00279     }
00280 }
00281 
00285 void DDXParser::process_attribute_alias(const char **attrs)
00286 {
00287     transfer_attrs(attrs);
00288     if (check_required_attribute(string("name"))
00289         && check_required_attribute(string("attribute"))) {
00290         set_state(inside_alias);
00291         at_stack.top()->attr_alias(attributes["name"],
00292                                    attributes["attribute"]);
00293     }
00294 }
00295 
00303 void DDXParser::process_variable(Type t, ParseState s, const char **attrs)
00304 {
00305     transfer_attrs(attrs);
00306 
00307     set_state(s);
00308     BaseType *btp = factory(t, attributes["name"]);
00309     if (!btp)
00310         ddx_fatal_error(this,
00311                         "Internal parser error; could not instantiate the variable '%s'.",
00312                         attributes["name"].c_str());
00313 
00314     // Once we make the new variable, we not only load it on to the
00315     // BaseType stack, we also load its AttrTable on the AttrTable stack.
00316     // The attribute processing software always operates on the AttrTable
00317     // at the top of the AttrTable stack (at_stack).
00318     bt_stack.push(btp);
00319     at_stack.push(&btp->get_attr_table());
00320 }
00321 
00325 void DDXParser::process_dimension(const char **attrs)
00326 {
00327     transfer_attrs(attrs);
00328     if (check_required_attribute(string("size"))) {
00329         set_state(inside_dimension);
00330         Array *ap = dynamic_cast < Array * >(bt_stack.top());
00331 
00332         ap->append_dim(atoi(attributes["size"].c_str()),
00333                        attributes["name"]);
00334     }
00335 }
00336 
00341 void DDXParser::process_blob(const char **attrs)
00342 {
00343     transfer_attrs(attrs);
00344     if (check_required_attribute(string("href"))) {
00345         set_state(inside_blob_href);
00346         *blob_href = attributes["href"];
00347     }
00348 }
00349 
00356 inline bool
00357 DDXParser::is_attribute_or_alias(const char *name, const char **attrs)
00358 {
00359     if (strcmp(name, "Attribute") == 0) {
00360         process_attribute_element(attrs);
00361         // next state: inside_attribtue or inside_attribute_container
00362         return true;
00363     }
00364     else if (strcmp(name, "Alias") == 0) {
00365         process_attribute_alias(attrs);
00366         // next state: inside_alias
00367         return true;
00368     }
00369 
00370     return false;
00371 }
00372 
00378 inline bool DDXParser::is_variable(const char *name, const char **attrs)
00379 {
00380     Type t;
00381     if ((t = is_simple_type(name)) != dods_null_c) {
00382         process_variable(t, inside_simple_type, attrs);
00383         return true;
00384     }
00385     else if (strcmp(name, "Array") == 0) {
00386         process_variable(dods_array_c, inside_array, attrs);
00387         return true;
00388     }
00389     else if (strcmp(name, "Structure") == 0) {
00390         process_variable(dods_structure_c, inside_structure, attrs);
00391         return true;
00392     }
00393     else if (strcmp(name, "Sequence") == 0) {
00394         process_variable(dods_sequence_c, inside_sequence, attrs);
00395         return true;
00396     }
00397     else if (strcmp(name, "Grid") == 0) {
00398         process_variable(dods_grid_c, inside_grid, attrs);
00399         return true;
00400     }
00401 
00402     return false;
00403 }
00404 
00405 void DDXParser::finish_variable(const char *tag, Type t,
00406                                 const char *expected)
00407 {
00408     if (strcmp(tag, expected) != 0) {
00409         DDXParser::ddx_fatal_error(this,
00410                                    "Expected an end tag for a %s; found '%s' instead.",
00411                                    expected, tag);
00412         return;
00413     }
00414 
00415     pop_state();
00416 
00417     BaseType *btp = bt_stack.top();
00418 
00419     bt_stack.pop();
00420     at_stack.pop();
00421 
00422     if (btp->type() != t) {
00423         DDXParser::ddx_fatal_error(this,
00424                                    "Internal error: Expected a %s variable.",
00425                                    expected);
00426         return;
00427     }
00428     // Once libxml2 validates, this can go away. 05/30/03 jhrg
00429     if (t == dods_array_c
00430         && dynamic_cast < Array * >(btp)->dimensions() == 0) {
00431         DDXParser::ddx_fatal_error(this,
00432                                    "No dimension element included in the Array '%s'.",
00433                                    btp->name().c_str());
00434         return;
00435     }
00436 
00437     BaseType *parent = bt_stack.top();
00438 
00439     if (!(parent->is_vector_type() || parent->is_constructor_type())) {
00440         DDXParser::ddx_fatal_error(this,
00441                                    "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
00442                                    tag,
00443                                    bt_stack.top()->type_name().c_str(),
00444                                    bt_stack.top()->name().c_str());
00445         return;
00446     }
00447 
00448     parent->add_var(btp);
00449 }
00450 
00457 
00462 void DDXParser::ddx_start_document(DDXParser * parser)
00463 {
00464     parser->error_msg = "";
00465     parser->char_data = "";
00466 
00467     // init attr table stack.
00468     parser->at_stack.push(&parser->dds->get_attr_table());
00469 
00470     // Trick; DDS *should* be a child of Structure. To simplify parsing,
00471     // stuff a Structure on the bt_stack and dump the top level variables
00472     // there. Once we're done, transfer the variables to the DDS.
00473     parser->bt_stack.push(new Structure("dummy_dds"));
00474 
00475     parser->set_state(parser_start);
00476 
00477     DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl);
00478 }
00479 
00482 void DDXParser::ddx_end_document(DDXParser * parser)
00483 {
00484     DBG2(cerr << "Ending state == " << states[parser->get_state()] <<
00485          endl);
00486 
00487     if (parser->get_state() != parser_start)
00488         DDXParser::ddx_fatal_error(parser,
00489                                    "The document contained unbalanced tags.");
00490 
00491     // If we've found any sort of error, don't make the DDX; intern() will
00492     // take care of the error.
00493     if (parser->get_state() == parser_error)
00494         return;
00495 
00496     // Pop the temporary Structure off the stack and transfer its variables
00497     // to the DDS.
00498     Constructor *cp =
00499         dynamic_cast < Constructor * >(parser->bt_stack.top());
00500     for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end();
00501          ++i)
00502         parser->dds->add_var(*i);
00503 
00504     parser->bt_stack.pop();
00505     delete cp;
00506 }
00507 
00514 void DDXParser::ddx_start_element(DDXParser * parser, const char *name,
00515                                   const char **attrs)
00516 {
00517     DBG2(cerr << "start element: " << name << ", states: "
00518          << states[parser->get_state()]);
00519 
00520     switch (parser->get_state()) {
00521     case parser_start:
00522         if (strcmp(name, "Dataset") == 0) {
00523             parser->set_state(inside_dataset);
00524 
00525             parser->transfer_attrs(attrs);
00526             if (parser->check_required_attribute(string("name")))
00527                 parser->dds->set_dataset_name(parser->attributes["name"]);
00528         }
00529         else
00530             DDXParser::ddx_fatal_error(parser,
00531                                        "Expected response to start with a Dataset element; found '%s' instead.",
00532                                        name);
00533         break;
00534 
00535     case inside_dataset:
00536         if (parser->is_attribute_or_alias(name, attrs))
00537             break;
00538         else if (parser->is_variable(name, attrs))
00539             break;
00540         else if (strcmp(name, "dataBLOB") == 0) {
00541             parser->process_blob(attrs);
00542             // next state: inside_data_blob
00543         }
00544         else
00545             DDXParser::ddx_fatal_error(parser,
00546                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00547                                        name);
00548         break;
00549 
00550     case inside_attribute_container:
00551         if (parser->is_attribute_or_alias(name, attrs))
00552             break;
00553         else
00554             DDXParser::ddx_fatal_error(parser,
00555                                        "Expected an Attribute or Alias element; found '%s' instead.",
00556                                        name);
00557         break;
00558 
00559     case inside_attribute:
00560         if (parser->is_attribute_or_alias(name, attrs))
00561             break;
00562         else if (strcmp(name, "value") == 0)
00563             parser->set_state(inside_attribute_value);
00564         else
00565             ddx_fatal_error(parser,
00566                             "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
00567                             name);
00568         break;
00569 
00570     case inside_attribute_value:
00571         ddx_fatal_error(parser,
00572                         "Internal parser error; unexpected state, inside value while processing element '%s'.",
00573                         name);
00574         break;
00575 
00576     case inside_alias:
00577         ddx_fatal_error(parser,
00578                         "Internal parser error; unexpected state, inside alias while processing element '%s'.",
00579                         name);
00580         break;
00581 
00582     case inside_simple_type:
00583         if (parser->is_attribute_or_alias(name, attrs))
00584             break;
00585         else
00586             ddx_fatal_error(parser,
00587                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00588                             name);
00589         break;
00590 
00591     case inside_array:
00592         if (parser->is_attribute_or_alias(name, attrs))
00593             break;
00594         else if (is_not(name, "Array") && parser->is_variable(name, attrs))
00595             break;
00596         else if (strcmp(name, "dimension") == 0) {
00597             parser->process_dimension(attrs);
00598             // next state: inside_dimension
00599         }
00600         else
00601             ddx_fatal_error(parser,
00602                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00603                             name);
00604         break;
00605 
00606     case inside_dimension:
00607         ddx_fatal_error(parser,
00608                         "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
00609                         name);
00610         break;
00611 
00612     case inside_structure:
00613         if (parser->is_attribute_or_alias(name, attrs))
00614             break;
00615         else if (parser->is_variable(name, attrs))
00616             break;
00617         else
00618             DDXParser::ddx_fatal_error(parser,
00619                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00620                                        name);
00621         break;
00622 
00623     case inside_sequence:
00624         if (parser->is_attribute_or_alias(name, attrs))
00625             break;
00626         else if (parser->is_variable(name, attrs))
00627             break;
00628         else
00629             DDXParser::ddx_fatal_error(parser,
00630                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00631                                        name);
00632         break;
00633 
00634     case inside_grid:
00635         if (parser->is_attribute_or_alias(name, attrs))
00636             break;
00637         else if (strcmp(name, "Array") == 0)
00638             parser->process_variable(dods_array_c, inside_array, attrs);
00639         else if (strcmp(name, "Map") == 0)
00640             parser->process_variable(dods_array_c, inside_map, attrs);
00641         else
00642             DDXParser::ddx_fatal_error(parser,
00643                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00644                                        name);
00645         break;
00646 
00647     case inside_map:
00648         if (parser->is_attribute_or_alias(name, attrs))
00649             break;
00650         else if (is_not(name, "Array") && is_not(name, "Sequence")
00651                  && is_not(name, "Grid")
00652                  && parser->is_variable(name, attrs))
00653             break;
00654         else if (strcmp(name, "dimension") == 0) {
00655             parser->process_dimension(attrs);
00656             // next state: inside_dimension
00657         }
00658         else
00659             ddx_fatal_error(parser,
00660                             "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
00661                             name);
00662         break;
00663 
00664     case inside_blob_href:
00665         ddx_fatal_error(parser,
00666                         "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
00667                         name);
00668         break;
00669 
00670     case parser_unknown:
00671         parser->set_state(parser_unknown);
00672         break;
00673 
00674     case parser_error:
00675         break;
00676     }
00677 
00678     DBGN(cerr << " ... " << states[parser->get_state()] << endl);
00679 }
00680 
00686 void DDXParser::ddx_end_element(DDXParser * parser, const char *name)
00687 {
00688     DBG2(cerr << "End element " << name << " (state "
00689          << states[parser->get_state()] << ")" << endl);
00690 
00691     switch (parser->get_state()) {
00692     case parser_start:
00693         ddx_fatal_error(parser,
00694                         "Internal parser error; unexpected state, inside start state while processing element '%s'.",
00695                         name);
00696         break;
00697 
00698     case inside_dataset:
00699         if (strcmp(name, "Dataset") == 0)
00700             parser->pop_state();
00701         else
00702             DDXParser::ddx_fatal_error(parser,
00703                                        "Expected an end Dataset tag; found '%s' instead.",
00704                                        name);
00705         break;
00706 
00707     case inside_attribute_container:
00708         if (strcmp(name, "Attribute") == 0) {
00709             parser->pop_state();
00710             parser->at_stack.pop();     // pop when leaving a container.
00711         }
00712         else
00713             DDXParser::ddx_fatal_error(parser,
00714                                        "Expected an end Attribute tag; found '%s' instead.",
00715                                        name);
00716         break;
00717 
00718     case inside_attribute:
00719         if (strcmp(name, "Attribute") == 0)
00720             parser->pop_state();
00721         else
00722             DDXParser::ddx_fatal_error(parser,
00723                                        "Expected an end Attribute tag; found '%s' instead.",
00724                                        name);
00725         break;
00726 
00727     case inside_attribute_value:
00728         if (strcmp(name, "value") == 0) {
00729             parser->pop_state();
00730             AttrTable *atp = parser->at_stack.top();
00731             atp->append_attr(parser->dods_attr_name,
00732                              parser->dods_attr_type, parser->char_data);
00733             parser->char_data = "";     // Null this after use.
00734         }
00735         else
00736             DDXParser::ddx_fatal_error(parser,
00737                                        "Expected an end value tag; found '%s' instead.",
00738                                        name);
00739 
00740         break;
00741 
00742         // Alias is busted in C++ 05/29/03 jhrg
00743     case inside_alias:
00744         parser->pop_state();
00745         break;
00746 
00747     case inside_simple_type:
00748         if (is_simple_type(name) != dods_null_c) {
00749             parser->pop_state();
00750             BaseType *btp = parser->bt_stack.top();
00751             parser->bt_stack.pop();
00752             parser->at_stack.pop();
00753 
00754             BaseType *parent = parser->bt_stack.top();
00755 
00756             if (parent->is_vector_type() || parent->is_constructor_type())
00757                 parent->add_var(btp);
00758             else
00759                 DDXParser::ddx_fatal_error(parser,
00760                                            "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
00761                                            name,
00762                                            parser->bt_stack.top()->
00763                                            type_name().c_str(),
00764                                            parser->bt_stack.top()->name().
00765                                            c_str());
00766         }
00767         else
00768             DDXParser::ddx_fatal_error(parser,
00769                                        "Expected an end tag for a simple type; found '%s' instead.",
00770                                        name);
00771         break;
00772 
00773     case inside_array:
00774         parser->finish_variable(name, dods_array_c, "Array");
00775         break;
00776 
00777     case inside_dimension:
00778         if (strcmp(name, "dimension") == 0)
00779             parser->pop_state();
00780         else
00781             DDXParser::ddx_fatal_error(parser,
00782                                        "Expected an end dimension tag; found '%s' instead.",
00783                                        name);
00784         break;
00785 
00786     case inside_structure:
00787         parser->finish_variable(name, dods_structure_c, "Structure");
00788         break;
00789 
00790     case inside_sequence:
00791         parser->finish_variable(name, dods_sequence_c, "Sequence");
00792         break;
00793 
00794     case inside_grid:
00795         parser->finish_variable(name, dods_grid_c, "Grid");
00796         break;
00797 
00798     case inside_map:
00799         parser->finish_variable(name, dods_array_c, "Map");
00800         break;
00801 
00802     case inside_blob_href:
00803         if (strcmp(name, "dataBLOB") == 0)
00804             parser->pop_state();
00805         else
00806             DDXParser::ddx_fatal_error(parser,
00807                                        "Expected an end dataBLOB tag; found '%s' instead.",
00808                                        name);
00809         break;
00810 
00811     case parser_unknown:
00812         parser->pop_state();
00813         break;
00814 
00815     case parser_error:
00816         break;
00817     }
00818 }
00819 
00823 void DDXParser::characters(DDXParser * parser, const xmlChar * ch, int len)
00824 {
00825     switch (parser->get_state()) {
00826     case inside_attribute_value:
00827         parser->char_data.append((const char *)(ch), len);
00828         DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl);
00829         break;
00830 
00831     default:
00832         break;
00833     }
00834 }
00835 
00840 xmlEntityPtr DDXParser::ddx_get_entity(DDXParser *, const xmlChar * name)
00841 {
00842     return xmlGetPredefinedEntity(name);
00843 }
00844 
00852 void DDXParser::ddx_fatal_error(DDXParser * parser, const char *msg, ...)
00853 {
00854     va_list args;
00855 
00856     parser->set_state(parser_error);
00857 
00858     va_start(args, msg);
00859     char str[1024];
00860     vsnprintf(str, 1024, msg, args);
00861     va_end(args);
00862 
00863 #ifdef LIBXML2_6_16
00864     // Defined if libxml2 >= 2.6.16
00865     int line = xmlSAX2GetLineNumber(parser->ctxt);
00866 #else
00867     int line = getLineNumber(parser->ctxt);
00868 #endif
00869     parser->error_msg += "At line " + long_to_string(line) + ": ";
00870     parser->error_msg += string(str) + string("\n");
00871 }
00872 
00874 
00877 static xmlSAXHandler ddx_sax_parser =
00878     {
00879         0,                          // internalSubset
00880         0,                          // isStandalone
00881         0,                          // hasInternalSubset
00882         0,                          // hasExternalSubset
00883         0,                          // resolveEntity
00884         (getEntitySAXFunc) DDXParser::ddx_get_entity,       // getEntity
00885         0,                          // entityDecl
00886         0,                          // notationDecl
00887         0,                          // attributeDecl
00888         0,                          // elementDecl
00889         0,                          // unparsedEntityDecl
00890         0,                          // setDocumentLocator
00891         (startDocumentSAXFunc) DDXParser::ddx_start_document,       // startDocument
00892         (endDocumentSAXFunc) DDXParser::ddx_end_document,   // endDocument
00893         (startElementSAXFunc) DDXParser::ddx_start_element, // startElement
00894         (endElementSAXFunc) DDXParser::ddx_end_element,     // endElement
00895         0,                          // reference
00896         (charactersSAXFunc) DDXParser::characters,
00897         0,                          // ignorableWhitespace
00898         0,                          // processingInstruction
00899         0,                          // (commentSAXFunc)gladeComment,  comment
00900         (warningSAXFunc) DDXParser::ddx_fatal_error,        // warning
00901         (errorSAXFunc) DDXParser::ddx_fatal_error,  // error
00902         (fatalErrorSAXFunc) DDXParser::ddx_fatal_error,     // fatalError
00903 #ifdef LIBXML2_5_10
00904         0,                          // getParameterEntity
00905         0,                          // cdataBlock
00906         0,                          // externalSubset
00907         0,                          // initialized
00908 #endif
00909 #ifdef LIBXML2_6_16
00910         0,                          // _private
00911         0,                          // endElementNs
00912         0,                          // serror
00913         0                           // startElementNs
00914 #endif
00915     };
00916 
00917 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context) const
00918 {
00919     if (!context->wellFormed) {
00920         context->sax = NULL;
00921         xmlFreeParserCtxt(context);
00922         throw
00923         DDXParseFailed(string
00924                        ("\nThe DDX is not a well formed XML document.\n")
00925                        + error_msg);
00926     }
00927 
00928     if (!context->valid) {
00929         context->sax = NULL;
00930         xmlFreeParserCtxt(context);
00931         throw DDXParseFailed(string("\nThe DDX is not a valid document.\n")
00932                              + error_msg);
00933     }
00934 
00935     if (get_state() == parser_error) {
00936         context->sax = NULL;
00937         xmlFreeParserCtxt(context);
00938         throw DDXParseFailed(string("\nError parsing DDX response.\n") +
00939                              error_msg);
00940     }
00941 
00942     context->sax = NULL;
00943     xmlFreeParserCtxt(context);
00944 }
00945 
00948 void DDXParser::intern_stream(FILE * in, DDS * dest_dds, string * blob)
00949 {
00950 // Code example from libxml2 docs re: read from a stream.
00951 
00952     if (!in || feof(in) || ferror(in))
00953         throw InternalErr(__FILE__, __LINE__,
00954                           "Input stream not open or read error");
00955 
00956     dds = dest_dds;             // dump values here
00957     blob_href = blob;           // blob goes here
00958 
00959     int size = 1024;
00960     char chars[1024];
00961 
00962     int res = fread(chars, 1, 4, in);
00963     if (res > 0) {
00964         xmlParserCtxtPtr context =
00965             xmlCreatePushParserCtxt(NULL, NULL, chars, res,
00966                                     "stream");
00967 
00968         ctxt = context;         // need ctxt for error messages
00969 
00970         context->sax = &ddx_sax_parser;
00971         context->userData = this;
00972         context->validate = true;
00973 
00974         while ((res = fread(chars, 1, size, in)) > 0) {
00975             xmlParseChunk(ctxt, chars, res, 0);
00976         }
00977         xmlParseChunk(ctxt, chars, 0, 1);
00978 
00979         cleanup_parse(context);
00980     }
00981 }
00982 
00983 
00995 void DDXParser::intern(const string & document, DDS * dest_dds,
00996                        string * blob)
00997 {
00998     // Create the context pointer explicitly so that we can store a pointer
00999     // to it in the DDXParser instance. This provides a way to generate our
01000     // own error messages *with* line numbers. The messages are pretty
01001     // meaningless otherwise. This means that we use an interface from the
01002     // 'parser internals' header, and not the 'parser' header. However, this
01003     // interface is also used in one of the documented examples, so it's
01004     // probably pretty stable. 06/02/03 jhrg
01005     xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
01006     if (!context)
01007         throw
01008         DDXParseFailed(string
01009                        ("Could not initialize the parser with the file: '")
01010                        + document + string("'."));
01011 
01012     dds = dest_dds;             // dump values here
01013     blob_href = blob;           // blob goes here
01014     ctxt = context;             // need ctxt for error messages
01015 
01016     context->sax = &ddx_sax_parser;
01017     context->userData = this;
01018     context->validate = true;
01019 
01020     xmlParseDocument(context);
01021 
01022     cleanup_parse(context);
01023 }

Generated on Wed Jun 27 12:56:39 2007 for libdap++ by  doxygen 1.4.7