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     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                 if (!ap)
00332                         ddx_fatal_error(this, "Parse error: Expected an array variable.");
00333                         
00334         ap->append_dim(atoi(attributes["size"].c_str()),
00335                        attributes["name"]);
00336     }
00337 }
00338 
00343 void DDXParser::process_blob(const char **attrs)
00344 {
00345     transfer_attrs(attrs);
00346     if (check_required_attribute(string("href"))) {
00347         set_state(inside_blob_href);
00348         *blob_href = attributes["href"];
00349     }
00350 }
00351 
00358 inline bool
00359 DDXParser::is_attribute_or_alias(const char *name, const char **attrs)
00360 {
00361     if (strcmp(name, "Attribute") == 0) {
00362         process_attribute_element(attrs);
00363         // next state: inside_attribtue or inside_attribute_container
00364         return true;
00365     }
00366     else if (strcmp(name, "Alias") == 0) {
00367         process_attribute_alias(attrs);
00368         // next state: inside_alias
00369         return true;
00370     }
00371 
00372     return false;
00373 }
00374 
00380 inline bool DDXParser::is_variable(const char *name, const char **attrs)
00381 {
00382     Type t;
00383     if ((t = is_simple_type(name)) != dods_null_c) {
00384         process_variable(t, inside_simple_type, attrs);
00385         return true;
00386     }
00387     else if (strcmp(name, "Array") == 0) {
00388         process_variable(dods_array_c, inside_array, attrs);
00389         return true;
00390     }
00391     else if (strcmp(name, "Structure") == 0) {
00392         process_variable(dods_structure_c, inside_structure, attrs);
00393         return true;
00394     }
00395     else if (strcmp(name, "Sequence") == 0) {
00396         process_variable(dods_sequence_c, inside_sequence, attrs);
00397         return true;
00398     }
00399     else if (strcmp(name, "Grid") == 0) {
00400         process_variable(dods_grid_c, inside_grid, attrs);
00401         return true;
00402     }
00403 
00404     return false;
00405 }
00406 
00407 void DDXParser::finish_variable(const char *tag, Type t,
00408                                 const char *expected)
00409 {
00410     if (strcmp(tag, expected) != 0) {
00411         DDXParser::ddx_fatal_error(this,
00412                                    "Expected an end tag for a %s; found '%s' instead.",
00413                                    expected, tag);
00414         return;
00415     }
00416 
00417     pop_state();
00418 
00419     BaseType *btp = bt_stack.top();
00420 
00421     bt_stack.pop();
00422     at_stack.pop();
00423 
00424     if (btp->type() != t) {
00425         DDXParser::ddx_fatal_error(this,
00426                                    "Internal error: Expected a %s variable.",
00427                                    expected);
00428         return;
00429     }
00430     // Once libxml2 validates, this can go away. 05/30/03 jhrg
00431     if (t == dods_array_c
00432         && dynamic_cast < Array * >(btp)->dimensions() == 0) {
00433         DDXParser::ddx_fatal_error(this,
00434                                    "No dimension element included in the Array '%s'.",
00435                                    btp->name().c_str());
00436         return;
00437     }
00438 
00439     BaseType *parent = bt_stack.top();
00440 
00441     if (!(parent->is_vector_type() || parent->is_constructor_type())) {
00442         DDXParser::ddx_fatal_error(this,
00443                                    "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
00444                                    tag,
00445                                    bt_stack.top()->type_name().c_str(),
00446                                    bt_stack.top()->name().c_str());
00447         return;
00448     }
00449 
00450     parent->add_var(btp);
00451 }
00452 
00459 
00464 void DDXParser::ddx_start_document(DDXParser * parser)
00465 {
00466     parser->error_msg = "";
00467     parser->char_data = "";
00468 
00469     // init attr table stack.
00470     parser->at_stack.push(&parser->dds->get_attr_table());
00471 
00472     // Trick; DDS *should* be a child of Structure. To simplify parsing,
00473     // stuff a Structure on the bt_stack and dump the top level variables
00474     // there. Once we're done, transfer the variables to the DDS.
00475     parser->bt_stack.push(new Structure("dummy_dds"));
00476 
00477     parser->set_state(parser_start);
00478 
00479     DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl);
00480 }
00481 
00484 void DDXParser::ddx_end_document(DDXParser * parser)
00485 {
00486     DBG2(cerr << "Ending state == " << states[parser->get_state()] <<
00487          endl);
00488 
00489     if (parser->get_state() != parser_start)
00490         DDXParser::ddx_fatal_error(parser,
00491                                    "The document contained unbalanced tags.");
00492 
00493     // If we've found any sort of error, don't make the DDX; intern() will
00494     // take care of the error.
00495     if (parser->get_state() == parser_error)
00496         return;
00497 
00498     // Pop the temporary Structure off the stack and transfer its variables
00499     // to the DDS.
00500     Constructor *cp =
00501         dynamic_cast < Constructor * >(parser->bt_stack.top());
00502     if (!cp)
00503         ddx_fatal_error(parser, "Parse error: Expected a Structure, Sequence or Grid variable.");
00504         
00505     for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end();
00506          ++i)
00507         parser->dds->add_var(*i);
00508 
00509     parser->bt_stack.pop();
00510     delete cp;
00511 }
00512 
00519 void DDXParser::ddx_start_element(DDXParser * parser, const char *name,
00520                                   const char **attrs)
00521 {
00522     DBG2(cerr << "start element: " << name << ", states: "
00523          << states[parser->get_state()]);
00524 
00525     switch (parser->get_state()) {
00526     case parser_start:
00527         if (strcmp(name, "Dataset") == 0) {
00528             parser->set_state(inside_dataset);
00529 
00530             parser->transfer_attrs(attrs);
00531             if (parser->check_required_attribute(string("name")))
00532                 parser->dds->set_dataset_name(parser->attributes["name"]);
00533         }
00534         else
00535             DDXParser::ddx_fatal_error(parser,
00536                                        "Expected response to start with a Dataset element; found '%s' instead.",
00537                                        name);
00538         break;
00539 
00540     case inside_dataset:
00541         if (parser->is_attribute_or_alias(name, attrs))
00542             break;
00543         else if (parser->is_variable(name, attrs))
00544             break;
00545         else if (strcmp(name, "dataBLOB") == 0) {
00546             parser->process_blob(attrs);
00547             // next state: inside_data_blob
00548         }
00549         else
00550             DDXParser::ddx_fatal_error(parser,
00551                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00552                                        name);
00553         break;
00554 
00555     case inside_attribute_container:
00556         if (parser->is_attribute_or_alias(name, attrs))
00557             break;
00558         else
00559             DDXParser::ddx_fatal_error(parser,
00560                                        "Expected an Attribute or Alias element; found '%s' instead.",
00561                                        name);
00562         break;
00563 
00564     case inside_attribute:
00565         if (parser->is_attribute_or_alias(name, attrs))
00566             break;
00567         else if (strcmp(name, "value") == 0)
00568             parser->set_state(inside_attribute_value);
00569         else
00570             ddx_fatal_error(parser,
00571                             "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
00572                             name);
00573         break;
00574 
00575     case inside_attribute_value:
00576         ddx_fatal_error(parser,
00577                         "Internal parser error; unexpected state, inside value while processing element '%s'.",
00578                         name);
00579         break;
00580 
00581     case inside_alias:
00582         ddx_fatal_error(parser,
00583                         "Internal parser error; unexpected state, inside alias while processing element '%s'.",
00584                         name);
00585         break;
00586 
00587     case inside_simple_type:
00588         if (parser->is_attribute_or_alias(name, attrs))
00589             break;
00590         else
00591             ddx_fatal_error(parser,
00592                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00593                             name);
00594         break;
00595 
00596     case inside_array:
00597         if (parser->is_attribute_or_alias(name, attrs))
00598             break;
00599         else if (is_not(name, "Array") && parser->is_variable(name, attrs))
00600             break;
00601         else if (strcmp(name, "dimension") == 0) {
00602             parser->process_dimension(attrs);
00603             // next state: inside_dimension
00604         }
00605         else
00606             ddx_fatal_error(parser,
00607                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00608                             name);
00609         break;
00610 
00611     case inside_dimension:
00612         ddx_fatal_error(parser,
00613                         "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
00614                         name);
00615         break;
00616 
00617     case inside_structure:
00618         if (parser->is_attribute_or_alias(name, attrs))
00619             break;
00620         else if (parser->is_variable(name, attrs))
00621             break;
00622         else
00623             DDXParser::ddx_fatal_error(parser,
00624                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00625                                        name);
00626         break;
00627 
00628     case inside_sequence:
00629         if (parser->is_attribute_or_alias(name, attrs))
00630             break;
00631         else if (parser->is_variable(name, attrs))
00632             break;
00633         else
00634             DDXParser::ddx_fatal_error(parser,
00635                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00636                                        name);
00637         break;
00638 
00639     case inside_grid:
00640         if (parser->is_attribute_or_alias(name, attrs))
00641             break;
00642         else if (strcmp(name, "Array") == 0)
00643             parser->process_variable(dods_array_c, inside_array, attrs);
00644         else if (strcmp(name, "Map") == 0)
00645             parser->process_variable(dods_array_c, inside_map, attrs);
00646         else
00647             DDXParser::ddx_fatal_error(parser,
00648                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00649                                        name);
00650         break;
00651 
00652     case inside_map:
00653         if (parser->is_attribute_or_alias(name, attrs))
00654             break;
00655         else if (is_not(name, "Array") && is_not(name, "Sequence")
00656                  && is_not(name, "Grid")
00657                  && parser->is_variable(name, attrs))
00658             break;
00659         else if (strcmp(name, "dimension") == 0) {
00660             parser->process_dimension(attrs);
00661             // next state: inside_dimension
00662         }
00663         else
00664             ddx_fatal_error(parser,
00665                             "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
00666                             name);
00667         break;
00668 
00669     case inside_blob_href:
00670         ddx_fatal_error(parser,
00671                         "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
00672                         name);
00673         break;
00674 
00675     case parser_unknown:
00676         parser->set_state(parser_unknown);
00677         break;
00678 
00679     case parser_error:
00680         break;
00681     }
00682 
00683     DBGN(cerr << " ... " << states[parser->get_state()] << endl);
00684 }
00685 
00691 void DDXParser::ddx_end_element(DDXParser * parser, const char *name)
00692 {
00693     DBG2(cerr << "End element " << name << " (state "
00694          << states[parser->get_state()] << ")" << endl);
00695 
00696     switch (parser->get_state()) {
00697     case parser_start:
00698         ddx_fatal_error(parser,
00699                         "Internal parser error; unexpected state, inside start state while processing element '%s'.",
00700                         name);
00701         break;
00702 
00703     case inside_dataset:
00704         if (strcmp(name, "Dataset") == 0)
00705             parser->pop_state();
00706         else
00707             DDXParser::ddx_fatal_error(parser,
00708                                        "Expected an end Dataset tag; found '%s' instead.",
00709                                        name);
00710         break;
00711 
00712     case inside_attribute_container:
00713         if (strcmp(name, "Attribute") == 0) {
00714             parser->pop_state();
00715             parser->at_stack.pop();     // pop when leaving a container.
00716         }
00717         else
00718             DDXParser::ddx_fatal_error(parser,
00719                                        "Expected an end Attribute tag; found '%s' instead.",
00720                                        name);
00721         break;
00722 
00723     case inside_attribute:
00724         if (strcmp(name, "Attribute") == 0)
00725             parser->pop_state();
00726         else
00727             DDXParser::ddx_fatal_error(parser,
00728                                        "Expected an end Attribute tag; found '%s' instead.",
00729                                        name);
00730         break;
00731 
00732     case inside_attribute_value:
00733         if (strcmp(name, "value") == 0) {
00734             parser->pop_state();
00735             AttrTable *atp = parser->at_stack.top();
00736             atp->append_attr(parser->dods_attr_name,
00737                              parser->dods_attr_type, parser->char_data);
00738             parser->char_data = "";     // Null this after use.
00739         }
00740         else
00741             DDXParser::ddx_fatal_error(parser,
00742                                        "Expected an end value tag; found '%s' instead.",
00743                                        name);
00744 
00745         break;
00746 
00747         // Alias is busted in C++ 05/29/03 jhrg
00748     case inside_alias:
00749         parser->pop_state();
00750         break;
00751 
00752     case inside_simple_type:
00753         if (is_simple_type(name) != dods_null_c) {
00754             parser->pop_state();
00755             BaseType *btp = parser->bt_stack.top();
00756             parser->bt_stack.pop();
00757             parser->at_stack.pop();
00758 
00759             BaseType *parent = parser->bt_stack.top();
00760 
00761             if (parent->is_vector_type() || parent->is_constructor_type())
00762                 parent->add_var(btp);
00763             else
00764                 DDXParser::ddx_fatal_error(parser,
00765                                            "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
00766                                            name,
00767                                            parser->bt_stack.top()->
00768                                            type_name().c_str(),
00769                                            parser->bt_stack.top()->name().
00770                                            c_str());
00771         }
00772         else
00773             DDXParser::ddx_fatal_error(parser,
00774                                        "Expected an end tag for a simple type; found '%s' instead.",
00775                                        name);
00776         break;
00777 
00778     case inside_array:
00779         parser->finish_variable(name, dods_array_c, "Array");
00780         break;
00781 
00782     case inside_dimension:
00783         if (strcmp(name, "dimension") == 0)
00784             parser->pop_state();
00785         else
00786             DDXParser::ddx_fatal_error(parser,
00787                                        "Expected an end dimension tag; found '%s' instead.",
00788                                        name);
00789         break;
00790 
00791     case inside_structure:
00792         parser->finish_variable(name, dods_structure_c, "Structure");
00793         break;
00794 
00795     case inside_sequence:
00796         parser->finish_variable(name, dods_sequence_c, "Sequence");
00797         break;
00798 
00799     case inside_grid:
00800         parser->finish_variable(name, dods_grid_c, "Grid");
00801         break;
00802 
00803     case inside_map:
00804         parser->finish_variable(name, dods_array_c, "Map");
00805         break;
00806 
00807     case inside_blob_href:
00808         if (strcmp(name, "dataBLOB") == 0)
00809             parser->pop_state();
00810         else
00811             DDXParser::ddx_fatal_error(parser,
00812                                        "Expected an end dataBLOB tag; found '%s' instead.",
00813                                        name);
00814         break;
00815 
00816     case parser_unknown:
00817         parser->pop_state();
00818         break;
00819 
00820     case parser_error:
00821         break;
00822     }
00823 }
00824 
00828 void DDXParser::characters(DDXParser * parser, const xmlChar * ch, int len)
00829 {
00830     switch (parser->get_state()) {
00831     case inside_attribute_value:
00832         parser->char_data.append((const char *)(ch), len);
00833         DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl);
00834         break;
00835 
00836     default:
00837         break;
00838     }
00839 }
00840 
00845 xmlEntityPtr DDXParser::ddx_get_entity(DDXParser *, const xmlChar * name)
00846 {
00847     return xmlGetPredefinedEntity(name);
00848 }
00849 
00857 void DDXParser::ddx_fatal_error(DDXParser * parser, const char *msg, ...)
00858 {
00859     va_list args;
00860 
00861     parser->set_state(parser_error);
00862 
00863     va_start(args, msg);
00864     char str[1024];
00865     vsnprintf(str, 1024, msg, args);
00866     va_end(args);
00867 
00868 #ifdef LIBXML2_6_16
00869     // Defined if libxml2 >= 2.6.16
00870     int line = xmlSAX2GetLineNumber(parser->ctxt);
00871 #else
00872     int line = getLineNumber(parser->ctxt);
00873 #endif
00874     parser->error_msg += "At line " + long_to_string(line) + ": ";
00875     parser->error_msg += string(str) + string("\n");
00876 }
00877 
00879 
00882 static xmlSAXHandler ddx_sax_parser =
00883     {
00884         0,                          // internalSubset
00885         0,                          // isStandalone
00886         0,                          // hasInternalSubset
00887         0,                          // hasExternalSubset
00888         0,                          // resolveEntity
00889         (getEntitySAXFunc) DDXParser::ddx_get_entity,       // getEntity
00890         0,                          // entityDecl
00891         0,                          // notationDecl
00892         0,                          // attributeDecl
00893         0,                          // elementDecl
00894         0,                          // unparsedEntityDecl
00895         0,                          // setDocumentLocator
00896         (startDocumentSAXFunc) DDXParser::ddx_start_document,       // startDocument
00897         (endDocumentSAXFunc) DDXParser::ddx_end_document,   // endDocument
00898         (startElementSAXFunc) DDXParser::ddx_start_element, // startElement
00899         (endElementSAXFunc) DDXParser::ddx_end_element,     // endElement
00900         0,                          // reference
00901         (charactersSAXFunc) DDXParser::characters,
00902         0,                          // ignorableWhitespace
00903         0,                          // processingInstruction
00904         0,                          // (commentSAXFunc)gladeComment,  comment
00905         (warningSAXFunc) DDXParser::ddx_fatal_error,        // warning
00906         (errorSAXFunc) DDXParser::ddx_fatal_error,  // error
00907         (fatalErrorSAXFunc) DDXParser::ddx_fatal_error,     // fatalError
00908 #ifdef LIBXML2_5_10
00909         0,                          // getParameterEntity
00910         0,                          // cdataBlock
00911         0,                          // externalSubset
00912         0,                          // initialized
00913 #endif
00914 #ifdef LIBXML2_6_16
00915         0,                          // _private
00916         0,                          // endElementNs
00917         0,                          // serror
00918         0                           // startElementNs
00919 #endif
00920     };
00921 
00922 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context) const
00923 {
00924     if (!context->wellFormed) {
00925         context->sax = NULL;
00926         xmlFreeParserCtxt(context);
00927         throw
00928         DDXParseFailed(string
00929                        ("\nThe DDX is not a well formed XML document.\n")
00930                        + error_msg);
00931     }
00932 
00933     if (!context->valid) {
00934         context->sax = NULL;
00935         xmlFreeParserCtxt(context);
00936         throw DDXParseFailed(string("\nThe DDX is not a valid document.\n")
00937                              + error_msg);
00938     }
00939 
00940     if (get_state() == parser_error) {
00941         context->sax = NULL;
00942         xmlFreeParserCtxt(context);
00943         throw DDXParseFailed(string("\nError parsing DDX response.\n") +
00944                              error_msg);
00945     }
00946 
00947     context->sax = NULL;
00948     xmlFreeParserCtxt(context);
00949 }
00950 
00953 void DDXParser::intern_stream(FILE * in, DDS * dest_dds, string * blob)
00954 {
00955 // Code example from libxml2 docs re: read from a stream.
00956 
00957     if (!in || feof(in) || ferror(in))
00958         throw InternalErr(__FILE__, __LINE__,
00959                           "Input stream not open or read error");
00960 
00961     dds = dest_dds;             // dump values here
00962     blob_href = blob;           // blob goes here
00963 
00964     int size = 1024;
00965     char chars[1024];
00966 
00967     int res = fread(chars, 1, 4, in);
00968     if (res > 0) {
00969         xmlParserCtxtPtr context =
00970             xmlCreatePushParserCtxt(NULL, NULL, chars, res,
00971                                     "stream");
00972 
00973         ctxt = context;         // need ctxt for error messages
00974 
00975         context->sax = &ddx_sax_parser;
00976         context->userData = this;
00977         context->validate = true;
00978 
00979         while ((res = fread(chars, 1, size, in)) > 0) {
00980             xmlParseChunk(ctxt, chars, res, 0);
00981         }
00982         xmlParseChunk(ctxt, chars, 0, 1);
00983 
00984         cleanup_parse(context);
00985     }
00986 }
00987 
00988 
01000 void DDXParser::intern(const string & document, DDS * dest_dds,
01001                        string * blob)
01002 {
01003     // Create the context pointer explicitly so that we can store a pointer
01004     // to it in the DDXParser instance. This provides a way to generate our
01005     // own error messages *with* line numbers. The messages are pretty
01006     // meaningless otherwise. This means that we use an interface from the
01007     // 'parser internals' header, and not the 'parser' header. However, this
01008     // interface is also used in one of the documented examples, so it's
01009     // probably pretty stable. 06/02/03 jhrg
01010     xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
01011     if (!context)
01012         throw
01013         DDXParseFailed(string
01014                        ("Could not initialize the parser with the file: '")
01015                        + document + string("'."));
01016 
01017     dds = dest_dds;             // dump values here
01018     blob_href = blob;           // blob goes here
01019     ctxt = context;             // need ctxt for error messages
01020 
01021     context->sax = &ddx_sax_parser;
01022     context->userData = this;
01023     context->validate = true;
01024 
01025     xmlParseDocument(context);
01026 
01027     cleanup_parse(context);
01028 }
01029 
01030 } // namespace libdap

Generated on Tue Mar 4 18:01:54 2008 for libdap++ by  doxygen 1.5.1