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 <cstring>
00029 
00030 #include "BaseType.h"
00031 #include "Constructor.h"
00032 #include "DDXParser.h"
00033 
00034 #include "util.h"
00035 #include "debug.h"
00036 
00037 namespace libdap {
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 #if 0
00238     bool found = false;
00239     map < string, string >::iterator i;
00240     for (i = attributes.begin(); i != attributes.end(); ++i)
00241         if (i->first == attr)
00242             found = true;
00243 
00244     if (!found)
00245          ddx_fatal_error(this, "Required attribute '%s' not found.",
00246                          attr.c_str());
00247 
00248      return found;
00249 #endif
00250 #if 1
00251     map < string, string >::iterator i = attributes.find(attr);
00252     if (i == attributes.end())
00253         ddx_fatal_error(this, "Required attribute '%s' not found.",
00254                         attr.c_str());
00255     return true;
00256 #endif
00257 }
00258 
00264 bool DDXParser::check_attribute(const string & attr)
00265 {
00266     return (attributes.find(attr) != attributes.end());
00267 }
00268 
00274 void DDXParser::process_attribute_element(const char **attrs)
00275 {
00276     // These methods set the state to parser_error if a problem is found.
00277     transfer_attrs(attrs);
00278     bool error = !(check_required_attribute(string("name"))
00279                    && check_required_attribute(string("type")));
00280     if (error)
00281         return;
00282 
00283     if (attributes["type"] == "Container") {
00284         set_state(inside_attribute_container);
00285 
00286         AttrTable *child;
00287         AttrTable *parent = at_stack.top();
00288 
00289         child = parent->append_container(attributes["name"]);
00290         at_stack.push(child);   // save.
00291         DBG2(cerr << "Pushing at" << endl);
00292     }
00293     else {
00294         set_state(inside_attribute);
00295 
00296         dods_attr_name = attributes["name"];
00297         dods_attr_type = attributes["type"];
00298     }
00299 }
00300 
00304 void DDXParser::process_attribute_alias(const char **attrs)
00305 {
00306     transfer_attrs(attrs);
00307     if (check_required_attribute(string("name"))
00308         && check_required_attribute(string("attribute"))) {
00309         set_state(inside_alias);
00310         at_stack.top()->attr_alias(attributes["name"],
00311                                    attributes["attribute"]);
00312     }
00313 }
00314 
00322 void DDXParser::process_variable(Type t, ParseState s, const char **attrs)
00323 {
00324     transfer_attrs(attrs);
00325 
00326     set_state(s);
00327     if (bt_stack.top()->type() == dods_array_c
00328             || check_required_attribute("name")) { // throws on error/false
00329         BaseType *btp = factory(t, attributes["name"]);
00330         if (!btp)
00331             ddx_fatal_error(
00332                     this,
00333                     "Internal parser error; could not instantiate the variable '%s'.",
00334                     attributes["name"].c_str());
00335 
00336         // Once we make the new variable, we not only load it on to the
00337         // BaseType stack, we also load its AttrTable on the AttrTable stack.
00338         // The attribute processing software always operates on the AttrTable
00339         // at the top of the AttrTable stack (at_stack).
00340         bt_stack.push(btp);
00341         at_stack.push(&btp->get_attr_table());
00342     }
00343 }
00344 
00348 void DDXParser::process_dimension(const char **attrs)
00349 {
00350     transfer_attrs(attrs);
00351     if (check_required_attribute(string("size"))) {
00352         set_state(inside_dimension);
00353         Array *ap = dynamic_cast<Array *> (bt_stack.top());
00354         if (!ap)
00355             ddx_fatal_error(this, "Parse error: Expected an array variable.");
00356         else
00357             ap->append_dim(atoi(attributes["size"].c_str()),
00358                     attributes["name"]);
00359     }
00360 }
00361 
00367 void DDXParser::process_blob(const char **attrs)
00368 {
00369     if (dds->get_dap_major() > 2 && dds->get_dap_major() > 1)
00370         ddx_fatal_error(this,
00371                 "Found a dataBLOB element in a 3.2 or greater response.");
00372 
00373     transfer_attrs(attrs);
00374     if (check_required_attribute(string("href"))) {
00375         set_state(inside_blob_href);
00376 #if 0
00377         *blob_href = attributes["href"];
00378 #endif
00379     }
00380 }
00381 
00388 inline bool
00389 DDXParser::is_attribute_or_alias(const char *name, const char **attrs)
00390 {
00391     if (strcmp(name, "Attribute") == 0) {
00392         process_attribute_element(attrs);
00393         // next state: inside_attribtue or inside_attribute_container
00394         return true;
00395     }
00396     else if (strcmp(name, "Alias") == 0) {
00397         process_attribute_alias(attrs);
00398         // next state: inside_alias
00399         return true;
00400     }
00401 
00402     return false;
00403 }
00404 
00410 inline bool DDXParser::is_variable(const char *name, const char **attrs)
00411 {
00412     Type t;
00413     if ((t = is_simple_type(name)) != dods_null_c) {
00414         process_variable(t, inside_simple_type, attrs);
00415         return true;
00416     }
00417     else if (strcmp(name, "Array") == 0) {
00418         process_variable(dods_array_c, inside_array, attrs);
00419         return true;
00420     }
00421     else if (strcmp(name, "Structure") == 0) {
00422         process_variable(dods_structure_c, inside_structure, attrs);
00423         return true;
00424     }
00425     else if (strcmp(name, "Sequence") == 0) {
00426         process_variable(dods_sequence_c, inside_sequence, attrs);
00427         return true;
00428     }
00429     else if (strcmp(name, "Grid") == 0) {
00430         process_variable(dods_grid_c, inside_grid, attrs);
00431         return true;
00432     }
00433 
00434     return false;
00435 }
00436 
00437 void DDXParser::finish_variable(const char *tag, Type t,
00438                                 const char *expected)
00439 {
00440     if (strcmp(tag, expected) != 0) {
00441         DDXParser::ddx_fatal_error(this,
00442                                    "Expected an end tag for a %s; found '%s' instead.",
00443                                    expected, tag);
00444         return;
00445     }
00446 
00447     pop_state();
00448 
00449     BaseType *btp = bt_stack.top();
00450 
00451     bt_stack.pop();
00452     at_stack.pop();
00453 
00454     if (btp && btp->type() != t) {
00455         DDXParser::ddx_fatal_error(this,
00456                                    "Internal error: Expected a %s variable.",
00457                                    expected);
00458         return;
00459     }
00460     // Once libxml2 validates, this can go away. 05/30/03 jhrg
00461     if (t == dods_array_c
00462         && dynamic_cast < Array * >(btp)->dimensions() == 0) {
00463         DDXParser::ddx_fatal_error(this,
00464                                    "No dimension element included in the Array '%s'.",
00465                                    btp->name().c_str());
00466         return;
00467     }
00468 
00469     BaseType *parent = bt_stack.top();
00470 
00471     if (!(parent->is_vector_type() || parent->is_constructor_type())) {
00472         DDXParser::ddx_fatal_error(this,
00473                                    "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
00474                                    tag,
00475                                    bt_stack.top()->type_name().c_str(),
00476                                    bt_stack.top()->name().c_str());
00477         return;
00478     }
00479 
00480     parent->add_var(btp);
00481 }
00482 
00489 
00494 void DDXParser::ddx_start_document(DDXParser * parser)
00495 {
00496     parser->error_msg = "";
00497     parser->char_data = "";
00498 
00499     // init attr table stack.
00500     parser->at_stack.push(&parser->dds->get_attr_table());
00501 
00502     // Trick; DDS *should* be a child of Structure. To simplify parsing,
00503     // stuff a Structure on the bt_stack and dump the top level variables
00504     // there. Once we're done, transfer the variables to the DDS.
00505     parser->bt_stack.push(new Structure("dummy_dds"));
00506 
00507     parser->set_state(parser_start);
00508 
00509     DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl);
00510 }
00511 
00514 void DDXParser::ddx_end_document(DDXParser * parser)
00515 {
00516     DBG2(cerr << "Ending state == " << states[parser->get_state()] <<
00517          endl);
00518 
00519     if (parser->get_state() != parser_start)
00520         DDXParser::ddx_fatal_error(parser,
00521                                    "The document contained unbalanced tags.");
00522 
00523     // If we've found any sort of error, don't make the DDX; intern() will
00524     // take care of the error.
00525     if (parser->get_state() == parser_error)
00526         return;
00527 
00528     // Pop the temporary Structure off the stack and transfer its variables
00529     // to the DDS.
00530     Constructor *cp = dynamic_cast < Constructor * >(parser->bt_stack.top());
00531     if (!cp)
00532         ddx_fatal_error(parser,
00533                 "Parse error: Expected a Structure, Sequence or Grid variable.");
00534     else {
00535         for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); ++i)
00536             parser->dds->add_var(*i);
00537 
00538         parser->bt_stack.pop();
00539         delete cp;
00540     }
00541 }
00542 
00549 void DDXParser::ddx_start_element(DDXParser * parser, const char *name,
00550                                   const char **attrs)
00551 {
00552     DBG2(cerr << "start element: " << name << ", states: "
00553          << states[parser->get_state()]);
00554 
00555     switch (parser->get_state()) {
00556     case parser_start:
00557         if (strcmp(name, "Dataset") == 0) {
00558             parser->set_state(inside_dataset);
00559 
00560             parser->transfer_attrs(attrs);
00561 
00562             if (parser->check_required_attribute(string("name")))
00563                 parser->dds->set_dataset_name(parser->attributes["name"]);
00564 
00565             if (parser->check_attribute("dap_version"))
00566                 parser->dds->set_dap_version(parser->attributes["dap_version"]);
00567         }
00568         else
00569             DDXParser::ddx_fatal_error(parser,
00570                                        "Expected response to start with a Dataset element; found '%s' instead.",
00571                                        name);
00572         break;
00573 
00574     case inside_dataset:
00575         if (parser->is_attribute_or_alias(name, attrs))
00576             break;
00577         else if (parser->is_variable(name, attrs))
00578             break;
00579         else if (strcmp(name, "dataBLOB") == 0) {
00580             parser->process_blob(attrs);
00581             // next state: inside_data_blob
00582         }
00583         else
00584             DDXParser::ddx_fatal_error(parser,
00585                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00586                                        name);
00587         break;
00588 
00589     case inside_attribute_container:
00590         if (parser->is_attribute_or_alias(name, attrs))
00591             break;
00592         else
00593             DDXParser::ddx_fatal_error(parser,
00594                                        "Expected an Attribute or Alias element; found '%s' instead.",
00595                                        name);
00596         break;
00597 
00598     case inside_attribute:
00599         if (parser->is_attribute_or_alias(name, attrs))
00600             break;
00601         else if (strcmp(name, "value") == 0)
00602             parser->set_state(inside_attribute_value);
00603         else
00604             ddx_fatal_error(parser,
00605                             "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
00606                             name);
00607         break;
00608 
00609     case inside_attribute_value:
00610         ddx_fatal_error(parser,
00611                         "Internal parser error; unexpected state, inside value while processing element '%s'.",
00612                         name);
00613         break;
00614 
00615     case inside_alias:
00616         ddx_fatal_error(parser,
00617                         "Internal parser error; unexpected state, inside alias while processing element '%s'.",
00618                         name);
00619         break;
00620 
00621     case inside_simple_type:
00622         if (parser->is_attribute_or_alias(name, attrs))
00623             break;
00624         else
00625             ddx_fatal_error(parser,
00626                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00627                             name);
00628         break;
00629 
00630     case inside_array:
00631         if (parser->is_attribute_or_alias(name, attrs))
00632             break;
00633         else if (is_not(name, "Array") && parser->is_variable(name, attrs))
00634             break;
00635         else if (strcmp(name, "dimension") == 0) {
00636             parser->process_dimension(attrs);
00637             // next state: inside_dimension
00638         }
00639         else
00640             ddx_fatal_error(parser,
00641                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00642                             name);
00643         break;
00644 
00645     case inside_dimension:
00646         ddx_fatal_error(parser,
00647                         "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
00648                         name);
00649         break;
00650 
00651     case inside_structure:
00652         if (parser->is_attribute_or_alias(name, attrs))
00653             break;
00654         else if (parser->is_variable(name, attrs))
00655             break;
00656         else
00657             DDXParser::ddx_fatal_error(parser,
00658                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00659                                        name);
00660         break;
00661 
00662     case inside_sequence:
00663         if (parser->is_attribute_or_alias(name, attrs))
00664             break;
00665         else if (parser->is_variable(name, attrs))
00666             break;
00667         else
00668             DDXParser::ddx_fatal_error(parser,
00669                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00670                                        name);
00671         break;
00672 
00673     case inside_grid:
00674         if (parser->is_attribute_or_alias(name, attrs))
00675             break;
00676         else if (strcmp(name, "Array") == 0)
00677             parser->process_variable(dods_array_c, inside_array, attrs);
00678         else if (strcmp(name, "Map") == 0)
00679             parser->process_variable(dods_array_c, inside_map, attrs);
00680         else
00681             DDXParser::ddx_fatal_error(parser,
00682                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00683                                        name);
00684         break;
00685 
00686     case inside_map:
00687         if (parser->is_attribute_or_alias(name, attrs))
00688             break;
00689         else if (is_not(name, "Array") && is_not(name, "Sequence")
00690                  && is_not(name, "Grid")
00691                  && parser->is_variable(name, attrs))
00692             break;
00693         else if (strcmp(name, "dimension") == 0) {
00694             parser->process_dimension(attrs);
00695             // next state: inside_dimension
00696         }
00697         else
00698             ddx_fatal_error(parser,
00699                             "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
00700                             name);
00701         break;
00702 
00703     case inside_blob_href:
00704         ddx_fatal_error(parser,
00705                         "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
00706                         name);
00707         break;
00708 
00709     case parser_unknown:
00710         parser->set_state(parser_unknown);
00711         break;
00712 
00713     case parser_error:
00714         break;
00715     }
00716 
00717     DBGN(cerr << " ... " << states[parser->get_state()] << endl);
00718 }
00719 
00725 void DDXParser::ddx_end_element(DDXParser * parser, const char *name)
00726 {
00727     DBG2(cerr << "End element " << name << " (state "
00728          << states[parser->get_state()] << ")" << endl);
00729 
00730     switch (parser->get_state()) {
00731     case parser_start:
00732         ddx_fatal_error(parser,
00733                         "Internal parser error; unexpected state, inside start state while processing element '%s'.",
00734                         name);
00735         break;
00736 
00737     case inside_dataset:
00738         if (strcmp(name, "Dataset") == 0)
00739             parser->pop_state();
00740         else
00741             DDXParser::ddx_fatal_error(parser,
00742                                        "Expected an end Dataset tag; found '%s' instead.",
00743                                        name);
00744         break;
00745 
00746     case inside_attribute_container:
00747         if (strcmp(name, "Attribute") == 0) {
00748             parser->pop_state();
00749             parser->at_stack.pop();     // pop when leaving a container.
00750         }
00751         else
00752             DDXParser::ddx_fatal_error(parser,
00753                                        "Expected an end Attribute tag; found '%s' instead.",
00754                                        name);
00755         break;
00756 
00757     case inside_attribute:
00758         if (strcmp(name, "Attribute") == 0)
00759             parser->pop_state();
00760         else
00761             DDXParser::ddx_fatal_error(parser,
00762                                        "Expected an end Attribute tag; found '%s' instead.",
00763                                        name);
00764         break;
00765 
00766     case inside_attribute_value:
00767         if (strcmp(name, "value") == 0) {
00768             parser->pop_state();
00769             AttrTable *atp = parser->at_stack.top();
00770             atp->append_attr(parser->dods_attr_name,
00771                              parser->dods_attr_type, parser->char_data);
00772             parser->char_data = "";     // Null this after use.
00773         }
00774         else
00775             DDXParser::ddx_fatal_error(parser,
00776                                        "Expected an end value tag; found '%s' instead.",
00777                                        name);
00778 
00779         break;
00780 
00781         // Alias is busted in C++ 05/29/03 jhrg
00782     case inside_alias:
00783         parser->pop_state();
00784         break;
00785 
00786     case inside_simple_type:
00787         if (is_simple_type(name) != dods_null_c) {
00788             parser->pop_state();
00789             BaseType *btp = parser->bt_stack.top();
00790             parser->bt_stack.pop();
00791             parser->at_stack.pop();
00792 
00793             BaseType *parent = parser->bt_stack.top();
00794 
00795             if (parent->is_vector_type() || parent->is_constructor_type())
00796                 parent->add_var(btp);
00797             else
00798                 DDXParser::ddx_fatal_error(parser,
00799                                            "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
00800                                            name,
00801                                            parser->bt_stack.top()->
00802                                            type_name().c_str(),
00803                                            parser->bt_stack.top()->name().
00804                                            c_str());
00805         }
00806         else
00807             DDXParser::ddx_fatal_error(parser,
00808                                        "Expected an end tag for a simple type; found '%s' instead.",
00809                                        name);
00810         break;
00811 
00812     case inside_array:
00813         parser->finish_variable(name, dods_array_c, "Array");
00814         break;
00815 
00816     case inside_dimension:
00817         if (strcmp(name, "dimension") == 0)
00818             parser->pop_state();
00819         else
00820             DDXParser::ddx_fatal_error(parser,
00821                                        "Expected an end dimension tag; found '%s' instead.",
00822                                        name);
00823         break;
00824 
00825     case inside_structure:
00826         parser->finish_variable(name, dods_structure_c, "Structure");
00827         break;
00828 
00829     case inside_sequence:
00830         parser->finish_variable(name, dods_sequence_c, "Sequence");
00831         break;
00832 
00833     case inside_grid:
00834         parser->finish_variable(name, dods_grid_c, "Grid");
00835         break;
00836 
00837     case inside_map:
00838         parser->finish_variable(name, dods_array_c, "Map");
00839         break;
00840 
00841     case inside_blob_href:
00842         if (strcmp(name, "dataBLOB") == 0)
00843             parser->pop_state();
00844         else
00845             DDXParser::ddx_fatal_error(parser,
00846                                        "Expected an end dataBLOB tag; found '%s' instead.",
00847                                        name);
00848         break;
00849 
00850     case parser_unknown:
00851         parser->pop_state();
00852         break;
00853 
00854     case parser_error:
00855         break;
00856     }
00857 }
00858 
00862 void DDXParser::characters(DDXParser * parser, const xmlChar * ch, int len)
00863 {
00864     switch (parser->get_state()) {
00865     case inside_attribute_value:
00866         parser->char_data.append((const char *)(ch), len);
00867         DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl);
00868         break;
00869 
00870     default:
00871         break;
00872     }
00873 }
00874 
00879 xmlEntityPtr DDXParser::ddx_get_entity(DDXParser *, const xmlChar * name)
00880 {
00881     return xmlGetPredefinedEntity(name);
00882 }
00883 
00891 void DDXParser::ddx_fatal_error(DDXParser * parser, const char *msg, ...)
00892 {
00893     va_list args;
00894 
00895     parser->set_state(parser_error);
00896 
00897     va_start(args, msg);
00898     char str[1024];
00899     vsnprintf(str, 1024, msg, args);
00900     va_end(args);
00901 
00902 #ifdef LIBXML2_6_16
00903     // Defined if libxml2 >= 2.6.16
00904     int line = xmlSAX2GetLineNumber(parser->ctxt);
00905 #else
00906     int line = getLineNumber(parser->ctxt);
00907 #endif
00908     parser->error_msg += "At line " + long_to_string(line) + ": ";
00909     parser->error_msg += string(str) + string("\n");
00910 }
00911 
00913 
00916 static xmlSAXHandler ddx_sax_parser =
00917     {
00918         0,                          // internalSubset
00919         0,                          // isStandalone
00920         0,                          // hasInternalSubset
00921         0,                          // hasExternalSubset
00922         0,                          // resolveEntity
00923         (getEntitySAXFunc) DDXParser::ddx_get_entity,       // getEntity
00924         0,                          // entityDecl
00925         0,                          // notationDecl
00926         0,                          // attributeDecl
00927         0,                          // elementDecl
00928         0,                          // unparsedEntityDecl
00929         0,                          // setDocumentLocator
00930         (startDocumentSAXFunc) DDXParser::ddx_start_document,       // startDocument
00931         (endDocumentSAXFunc) DDXParser::ddx_end_document,   // endDocument
00932         (startElementSAXFunc) DDXParser::ddx_start_element, // startElement
00933         (endElementSAXFunc) DDXParser::ddx_end_element,     // endElement
00934         0,                          // reference
00935         (charactersSAXFunc) DDXParser::characters,
00936         0,                          // ignorableWhitespace
00937         0,                          // processingInstruction
00938         0,                          // (commentSAXFunc)gladeComment,  comment
00939         (warningSAXFunc) DDXParser::ddx_fatal_error,        // warning
00940         (errorSAXFunc) DDXParser::ddx_fatal_error,  // error
00941         (fatalErrorSAXFunc) DDXParser::ddx_fatal_error,     // fatalError
00942 #ifdef LIBXML2_5_10
00943         0,                          // getParameterEntity
00944         0,                          // cdataBlock
00945         0,                          // externalSubset
00946         0,                          // initialized
00947 #endif
00948 #ifdef LIBXML2_6_16
00949         0,                          // _private
00950         0,                          // endElementNs
00951         0,                          // serror
00952         0                           // startElementNs
00953 #endif
00954     };
00955 
00956 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context) const
00957 {
00958     if (!context->wellFormed) {
00959         context->sax = NULL;
00960         xmlFreeParserCtxt(context);
00961         throw
00962         DDXParseFailed(string
00963                        ("\nThe DDX is not a well formed XML document.\n")
00964                        + error_msg);
00965     }
00966 
00967     if (!context->valid) {
00968         context->sax = NULL;
00969         xmlFreeParserCtxt(context);
00970         throw DDXParseFailed(string("\nThe DDX is not a valid document.\n")
00971                              + error_msg);
00972     }
00973 
00974     if (get_state() == parser_error) {
00975         context->sax = NULL;
00976         xmlFreeParserCtxt(context);
00977         throw DDXParseFailed(string("\nError parsing DDX response.\n") +
00978                              error_msg);
00979     }
00980 
00981     context->sax = NULL;
00982     xmlFreeParserCtxt(context);
00983 }
00984 
00987 void DDXParser::intern_stream(FILE * in, DDS * dest_dds)
00988 {
00989 // Code example from libxml2 docs re: read from a stream.
00990 
00991     if (!in || feof(in) || ferror(in))
00992         throw InternalErr(__FILE__, __LINE__,
00993                           "Input stream not open or read error");
00994 
00995     dds = dest_dds;             // dump values here
00996 #if 0
00997     blob_href = blob;           // blob goes here
00998 #endif
00999     int size = 1024;
01000     char chars[1024];
01001 
01002     int res = fread(chars, 1, 4, in);
01003     if (res > 0) {
01004         xmlParserCtxtPtr context =
01005             xmlCreatePushParserCtxt(NULL, NULL, chars, res,
01006                                     "stream");
01007 
01008         ctxt = context;         // need ctxt for error messages
01009 
01010         context->sax = &ddx_sax_parser;
01011         context->userData = this;
01012         context->validate = true;
01013 
01014         while ((res = fread(chars, 1, size, in)) > 0) {
01015             xmlParseChunk(ctxt, chars, res, 0);
01016         }
01017         xmlParseChunk(ctxt, chars, 0, 1);
01018 
01019         cleanup_parse(context);
01020     }
01021 }
01022 
01023 
01036 void DDXParser::intern(const string & document, DDS * dest_dds)
01037 {
01038     // Create the context pointer explicitly so that we can store a pointer
01039     // to it in the DDXParser instance. This provides a way to generate our
01040     // own error messages *with* line numbers. The messages are pretty
01041     // meaningless otherwise. This means that we use an interface from the
01042     // 'parser internals' header, and not the 'parser' header. However, this
01043     // interface is also used in one of the documented examples, so it's
01044     // probably pretty stable. 06/02/03 jhrg
01045     xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
01046     if (!context)
01047         throw
01048         DDXParseFailed(string
01049                        ("Could not initialize the parser with the file: '")
01050                        + document + string("'."));
01051 
01052     dds = dest_dds;             // dump values here
01053 #if 0
01054     blob_href = blob;           // blob goes here
01055 #endif
01056     ctxt = context;             // need ctxt for error messages
01057 
01058     context->sax = &ddx_sax_parser;
01059     context->userData = this;
01060     context->validate = true;
01061 
01062     xmlParseDocument(context);
01063 
01064     cleanup_parse(context);
01065 }
01066 
01067 } // namespace libdap

Generated on Wed Apr 15 19:20:23 2009 for libdap++ by  doxygen 1.4.7