libdap++ Updated for version 3.8.2
|
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 //#define DODS_DEBUG 1 00029 //#define DODS_DEBUG2 1 00030 00031 #include <cstring> 00032 #include <cstdarg> 00033 00034 #include "BaseType.h" 00035 #include "Byte.h" 00036 #include "Int16.h" 00037 #include "UInt16.h" 00038 #include "Int32.h" 00039 #include "UInt32.h" 00040 #include "Float32.h" 00041 #include "Float64.h" 00042 #include "Str.h" 00043 #include "Url.h" 00044 #include "Array.h" 00045 #include "Structure.h" 00046 #include "Sequence.h" 00047 #include "Grid.h" 00048 00049 #include "DDXParserSAX2.h" 00050 00051 #include "util.h" 00052 #include "mime_util.h" 00053 #include "debug.h" 00054 00055 namespace libdap { 00056 00057 static const not_used char *states[] = 00058 { 00059 "start", 00060 00061 "dataset", 00062 00063 "attribute_container", 00064 "attribute", 00065 "attribute_value", 00066 "other_xml_attribute", 00067 00068 "alias", 00069 00070 "simple_type", 00071 00072 "array", 00073 "dimension", 00074 00075 "grid", 00076 "map", 00077 00078 "structure", 00079 "sequence", 00080 00081 "blob href", 00082 00083 "unknown", 00084 "error" 00085 }; 00086 00087 // Glue the BaseTypeFactory to the enum-based factory defined statically 00088 // here. 00089 00090 BaseType *DDXParser::factory(Type t, const string & name) 00091 { 00092 switch (t) { 00093 case dods_byte_c: 00094 return d_factory->NewByte(name); 00095 break; 00096 00097 case dods_int16_c: 00098 return d_factory->NewInt16(name); 00099 break; 00100 00101 case dods_uint16_c: 00102 return d_factory->NewUInt16(name); 00103 break; 00104 00105 case dods_int32_c: 00106 return d_factory->NewInt32(name); 00107 break; 00108 00109 case dods_uint32_c: 00110 return d_factory->NewUInt32(name); 00111 break; 00112 00113 case dods_float32_c: 00114 return d_factory->NewFloat32(name); 00115 break; 00116 00117 case dods_float64_c: 00118 return d_factory->NewFloat64(name); 00119 break; 00120 00121 case dods_str_c: 00122 return d_factory->NewStr(name); 00123 break; 00124 00125 case dods_url_c: 00126 return d_factory->NewUrl(name); 00127 break; 00128 00129 case dods_array_c: 00130 return d_factory->NewArray(name); 00131 break; 00132 00133 case dods_structure_c: 00134 return d_factory->NewStructure(name); 00135 break; 00136 00137 case dods_sequence_c: 00138 return d_factory->NewSequence(name); 00139 break; 00140 00141 case dods_grid_c: 00142 return d_factory->NewGrid(name); 00143 break; 00144 00145 default: 00146 return 0; 00147 } 00148 } 00149 00151 static Type get_type(const char *name) 00152 { 00153 if (strcmp(name, "Byte") == 0) 00154 return dods_byte_c; 00155 00156 if (strcmp(name, "Int16") == 0) 00157 return dods_int16_c; 00158 00159 if (strcmp(name, "UInt16") == 0) 00160 return dods_uint16_c; 00161 00162 if (strcmp(name, "Int32") == 0) 00163 return dods_int32_c; 00164 00165 if (strcmp(name, "UInt32") == 0) 00166 return dods_uint32_c; 00167 00168 if (strcmp(name, "Float32") == 0) 00169 return dods_float32_c; 00170 00171 if (strcmp(name, "Float64") == 0) 00172 return dods_float64_c; 00173 00174 if (strcmp(name, "String") == 0) 00175 return dods_str_c; 00176 00177 if (strcmp(name, "Url") == 0) 00178 return dods_url_c; 00179 00180 if (strcmp(name, "Array") == 0) 00181 return dods_array_c; 00182 00183 if (strcmp(name, "Structure") == 0) 00184 return dods_structure_c; 00185 00186 if (strcmp(name, "Sequence") == 0) 00187 return dods_sequence_c; 00188 00189 if (strcmp(name, "Grid") == 0) 00190 return dods_grid_c; 00191 00192 return dods_null_c; 00193 } 00194 00195 static Type is_simple_type(const char *name) 00196 { 00197 Type t = get_type(name); 00198 switch (t) { 00199 case dods_byte_c: 00200 case dods_int16_c: 00201 case dods_uint16_c: 00202 case dods_int32_c: 00203 case dods_uint32_c: 00204 case dods_float32_c: 00205 case dods_float64_c: 00206 case dods_str_c: 00207 case dods_url_c: 00208 return t; 00209 default: 00210 return dods_null_c; 00211 } 00212 } 00213 00214 static bool is_not(const char *name, const char *tag) 00215 { 00216 return strcmp(name, tag) != 0; 00217 } 00218 00219 void DDXParser::set_state(DDXParser::ParseState state) 00220 { 00221 s.push(state); 00222 } 00223 00224 DDXParser::ParseState DDXParser::get_state() const 00225 { 00226 return s.top(); 00227 } 00228 00229 void DDXParser::pop_state() 00230 { 00231 s.pop(); 00232 } 00233 00237 void DDXParser::transfer_xml_attrs(const xmlChar **attributes, int nb_attributes) 00238 { 00239 if (!attribute_table.empty()) 00240 attribute_table.clear(); // erase old attributes 00241 00242 unsigned int index = 0; 00243 for (int i = 0; i < nb_attributes; ++i, index += 5) { 00244 // Make a value using the attribute name and the prefix, namespace URI 00245 // and the value. The prefix might be null. 00246 attribute_table.insert(map<string, XMLAttribute>::value_type( 00247 string((const char *)attributes[index]), 00248 XMLAttribute(attributes + index + 1))); 00249 00250 DBG(cerr << "Attribute '" << (const char *)attributes[index] << "': " 00251 << attribute_table[(const char *)attributes[index]].value << endl); 00252 } 00253 } 00254 00255 void DDXParser::transfer_xml_ns(const xmlChar **namespaces, int nb_namespaces) 00256 { 00257 for (int i = 0; i < nb_namespaces; ++i ) { 00258 // make a value with the prefix and namespace URI. The prefix might be 00259 // null. 00260 namespace_table.insert(map<string,string>::value_type( 00261 namespaces[i*2] != 0 ? (const char *)namespaces[i*2] : "", 00262 (const char *)namespaces[i*2+1])); 00263 } 00264 } 00265 00270 bool DDXParser::check_required_attribute(const string & attr) 00271 { 00272 map < string, XMLAttribute >::iterator i = attribute_table.find(attr); 00273 if (i == attribute_table.end()) 00274 ddx_fatal_error(this, "Required attribute '%s' not found.", 00275 attr.c_str()); 00276 return true; 00277 } 00278 00284 bool DDXParser::check_attribute(const string & attr) 00285 { 00286 return (attribute_table.find(attr) != attribute_table.end()); 00287 } 00288 00297 void DDXParser::process_attribute_element(const xmlChar **attrs, int nb_attributes) 00298 { 00299 // These methods set the state to parser_error if a problem is found. 00300 transfer_xml_attrs(attrs, nb_attributes); 00301 00302 bool error = !(check_required_attribute(string("name")) 00303 && check_required_attribute(string("type"))); 00304 if (error) 00305 return; 00306 00307 if (attribute_table["type"].value == "Container") { 00308 set_state(inside_attribute_container); 00309 00310 AttrTable *child; 00311 AttrTable *parent = at_stack.top(); 00312 00313 child = parent->append_container(attribute_table["name"].value); 00314 at_stack.push(child); // save. 00315 DBG2(cerr << "Pushing at" << endl); 00316 } 00317 else if (attribute_table["type"].value == "OtherXML") { 00318 set_state(inside_other_xml_attribute); 00319 00320 dods_attr_name = attribute_table["name"].value; 00321 dods_attr_type = attribute_table["type"].value; 00322 } 00323 else { 00324 set_state(inside_attribute); 00325 // *** Modify parser. Add a special state for inside OtherXML since it 00326 // does not use the <value> element. 00327 00328 dods_attr_name = attribute_table["name"].value; 00329 dods_attr_type = attribute_table["type"].value; 00330 } 00331 } 00332 00336 void DDXParser::process_attribute_alias(const xmlChar **attrs, int nb_attributes) 00337 { 00338 transfer_xml_attrs(attrs, nb_attributes); 00339 if (check_required_attribute(string("name")) 00340 && check_required_attribute(string("attribute"))) { 00341 set_state(inside_alias); 00342 at_stack.top()->attr_alias(attribute_table["name"].value, 00343 attribute_table["attribute"].value); 00344 } 00345 } 00346 00354 void DDXParser::process_variable(Type t, ParseState s, const xmlChar **attrs, 00355 int nb_attributes) 00356 { 00357 transfer_xml_attrs(attrs, nb_attributes); 00358 00359 set_state(s); 00360 if (bt_stack.top()->type() == dods_array_c 00361 || check_required_attribute("name")) { // throws on error/false 00362 BaseType *btp = factory(t, attribute_table["name"].value); 00363 if (!btp) 00364 ddx_fatal_error( 00365 this, 00366 "Internal parser error; could not instantiate the variable '%s'.", 00367 attribute_table["name"].value.c_str()); 00368 00369 // Once we make the new variable, we not only load it on to the 00370 // BaseType stack, we also load its AttrTable on the AttrTable stack. 00371 // The attribute processing software always operates on the AttrTable 00372 // at the top of the AttrTable stack (at_stack). 00373 bt_stack.push(btp); 00374 at_stack.push(&btp->get_attr_table()); 00375 } 00376 } 00377 00381 void DDXParser::process_dimension(const xmlChar **attrs, int nb_attributes) 00382 { 00383 transfer_xml_attrs(attrs, nb_attributes); 00384 if (check_required_attribute(string("size"))) { 00385 set_state(inside_dimension); 00386 Array *ap = dynamic_cast < Array * >(bt_stack.top()); 00387 if (!ap) 00388 ddx_fatal_error(this, "Parse error: Expected an array variable."); 00389 00390 ap->append_dim(atoi(attribute_table["size"].value.c_str()), 00391 attribute_table["name"].value); 00392 } 00393 } 00394 00397 void DDXParser::process_blob(const xmlChar **attrs, int nb_attributes) 00398 { 00399 transfer_xml_attrs(attrs, nb_attributes); 00400 if (check_required_attribute(string("href"))) { 00401 set_state(inside_blob_href); 00402 *blob_href = attribute_table["href"].value; 00403 } 00404 } 00405 00412 inline bool 00413 DDXParser::is_attribute_or_alias(const char *name, const xmlChar **attrs, 00414 int nb_attributes) 00415 { 00416 if (strcmp(name, "Attribute") == 0) { 00417 process_attribute_element(attrs, nb_attributes); 00418 // next state: inside_attribtue or inside_attribute_container 00419 return true; 00420 } 00421 else if (strcmp(name, "Alias") == 0) { 00422 process_attribute_alias(attrs, nb_attributes); 00423 // next state: inside_alias 00424 return true; 00425 } 00426 00427 return false; 00428 } 00429 00435 inline bool DDXParser::is_variable(const char *name, const xmlChar **attrs, 00436 int nb_attributes) 00437 { 00438 Type t; 00439 if ((t = is_simple_type(name)) != dods_null_c) { 00440 process_variable(t, inside_simple_type, attrs, nb_attributes); 00441 return true; 00442 } 00443 else if (strcmp(name, "Array") == 0) { 00444 process_variable(dods_array_c, inside_array, attrs, nb_attributes); 00445 return true; 00446 } 00447 else if (strcmp(name, "Structure") == 0) { 00448 process_variable(dods_structure_c, inside_structure, attrs, nb_attributes); 00449 return true; 00450 } 00451 else if (strcmp(name, "Sequence") == 0) { 00452 process_variable(dods_sequence_c, inside_sequence, attrs, nb_attributes); 00453 return true; 00454 } 00455 else if (strcmp(name, "Grid") == 0) { 00456 process_variable(dods_grid_c, inside_grid, attrs, nb_attributes); 00457 return true; 00458 } 00459 00460 return false; 00461 } 00462 00463 void DDXParser::finish_variable(const char *tag, Type t, const char *expected) 00464 { 00465 if (strcmp(tag, expected) != 0) { 00466 DDXParser::ddx_fatal_error(this, 00467 "Expected an end tag for a %s; found '%s' instead.", 00468 expected, tag); 00469 return; 00470 } 00471 00472 pop_state(); 00473 00474 BaseType *btp = bt_stack.top(); 00475 00476 bt_stack.pop(); 00477 at_stack.pop(); 00478 00479 if (btp->type() != t) { 00480 DDXParser::ddx_fatal_error(this, 00481 "Internal error: Expected a %s variable.", 00482 expected); 00483 return; 00484 } 00485 // Once libxml2 validates, this can go away. 05/30/03 jhrg 00486 if (t == dods_array_c 00487 && dynamic_cast < Array * >(btp)->dimensions() == 0) { 00488 DDXParser::ddx_fatal_error(this, 00489 "No dimension element included in the Array '%s'.", 00490 btp->name().c_str()); 00491 return; 00492 } 00493 00494 BaseType *parent = bt_stack.top(); 00495 00496 if (!(parent->is_vector_type() || parent->is_constructor_type())) { 00497 DDXParser::ddx_fatal_error(this, 00498 "Tried to add the array variable '%s' to a non-constructor type (%s %s).", 00499 tag, 00500 bt_stack.top()->type_name().c_str(), 00501 bt_stack.top()->name().c_str()); 00502 return; 00503 } 00504 00505 parent->add_var(btp); 00506 } 00507 00514 00519 void DDXParser::ddx_start_document(void * p) 00520 { 00521 DDXParser *parser = static_cast<DDXParser*>(p); 00522 parser->error_msg = ""; 00523 parser->char_data = ""; 00524 00525 // init attr table stack. 00526 parser->at_stack.push(&parser->dds->get_attr_table()); 00527 00528 // Trick; DDS *should* be a child of Structure. To simplify parsing, 00529 // stuff a Structure on the bt_stack and dump the top level variables 00530 // there. Once we're done, transfer the variables to the DDS. 00531 parser->bt_stack.push(new Structure("dummy_dds")); 00532 00533 parser->set_state(parser_start); 00534 00535 DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl); 00536 } 00537 00540 void DDXParser::ddx_end_document(void * p) 00541 { 00542 DDXParser *parser = static_cast<DDXParser*>(p); 00543 DBG2(cerr << "Ending state == " << states[parser->get_state()] << 00544 endl); 00545 00546 if (parser->get_state() != parser_start) 00547 DDXParser::ddx_fatal_error(parser, 00548 "The document contained unbalanced tags."); 00549 00550 // If we've found any sort of error, don't make the DDX; intern() will 00551 // take care of the error. 00552 if (parser->get_state() == parser_error) 00553 return; 00554 00555 // Pop the temporary Structure off the stack and transfer its variables 00556 // to the DDS. 00557 Constructor *cp = dynamic_cast < Constructor * >(parser->bt_stack.top()); 00558 if (!cp) 00559 ddx_fatal_error(parser, "Parse error: Expected a Structure, Sequence or Grid variable."); 00560 00561 for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); 00562 ++i) 00563 parser->dds->add_var(*i); 00564 00565 parser->bt_stack.pop(); 00566 delete cp; 00567 } 00568 00569 void DDXParser::ddx_sax2_start_element(void *p, 00570 const xmlChar *l, const xmlChar *prefix, const xmlChar *URI, 00571 int nb_namespaces, const xmlChar **namespaces, 00572 int nb_attributes, int /*nb_defaulted*/, const xmlChar **attributes) 00573 { 00574 DDXParser *parser = static_cast<DDXParser*>(p); 00575 const char *localname = (const char *)l; 00576 00577 DBG2(cerr << "start element: " << localname << ", states: " 00578 << states[parser->get_state()]); 00579 00580 switch (parser->get_state()) { 00581 case parser_start: 00582 if (strcmp(localname, "Dataset") == 0) { 00583 parser->set_state(inside_dataset); 00584 parser->root_ns = URI != 0 ? (const char *)URI: ""; 00585 parser->transfer_xml_attrs(attributes, nb_attributes); 00586 00587 if (parser->check_required_attribute(string("name"))) 00588 parser->dds->set_dataset_name(parser->attribute_table["name"].value); 00589 00590 if (parser->check_attribute("dapVersion")) 00591 parser->dds->set_dap_version(parser->attribute_table["dapVersion"].value); 00592 } 00593 else 00594 DDXParser::ddx_fatal_error(parser, 00595 "Expected response to start with a Dataset element; found '%s' instead.", 00596 localname); 00597 break; 00598 00599 case inside_dataset: 00600 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00601 break; 00602 else if (parser->is_variable(localname, attributes, nb_attributes)) 00603 break; 00604 else if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0) { 00605 parser->process_blob(attributes, nb_attributes); 00606 // next state: inside_data_blob 00607 } 00608 else 00609 DDXParser::ddx_fatal_error(parser, 00610 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00611 localname); 00612 break; 00613 00614 case inside_attribute_container: 00615 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00616 break; 00617 else 00618 DDXParser::ddx_fatal_error(parser, 00619 "Expected an Attribute or Alias element; found '%s' instead.", 00620 localname); 00621 break; 00622 00623 case inside_attribute: 00624 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00625 break; 00626 else if (strcmp(localname, "value") == 0) 00627 parser->set_state(inside_attribute_value); 00628 else 00629 ddx_fatal_error(parser, 00630 "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.", 00631 localname); 00632 break; 00633 00634 case inside_attribute_value: 00635 ddx_fatal_error(parser, 00636 "Internal parser error; unexpected state, inside value while processing element '%s'.", 00637 localname); 00638 break; 00639 00640 case inside_other_xml_attribute: 00641 DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname << endl); 00642 00643 parser->other_xml_depth++; 00644 00645 // Accumulate the elements here 00646 00647 parser->other_xml.append("<"); 00648 if (prefix) { 00649 parser->other_xml.append((const char *)prefix); 00650 parser->other_xml.append(":"); 00651 } 00652 parser->other_xml.append(localname); 00653 00654 if (nb_namespaces != 0) { 00655 parser->transfer_xml_ns(namespaces, nb_namespaces); 00656 00657 for (map<string,string>::iterator i = parser->namespace_table.begin(); 00658 i != parser->namespace_table.end(); 00659 ++i) { 00660 parser->other_xml.append(" xmlns"); 00661 if (!i->first.empty()) { 00662 parser->other_xml.append(":"); 00663 parser->other_xml.append(i->first); 00664 } 00665 parser->other_xml.append("=\""); 00666 parser->other_xml.append(i->second); 00667 parser->other_xml.append("\""); 00668 } 00669 } 00670 00671 if (nb_attributes != 0) { 00672 parser->transfer_xml_attrs(attributes, nb_attributes); 00673 for (XMLAttrMap::iterator i = parser->attr_table_begin(); 00674 i != parser->attr_table_end(); 00675 ++i) { 00676 parser->other_xml.append(" "); 00677 if (!i->second.prefix.empty()) { 00678 parser->other_xml.append(i->second.prefix); 00679 parser->other_xml.append(":"); 00680 } 00681 parser->other_xml.append(i->first); 00682 parser->other_xml.append("=\""); 00683 parser->other_xml.append(i->second.value); 00684 parser->other_xml.append("\""); 00685 } 00686 } 00687 00688 parser->other_xml.append(">"); 00689 break; 00690 00691 case inside_alias: 00692 ddx_fatal_error(parser, 00693 "Internal parser error; unexpected state, inside alias while processing element '%s'.", 00694 localname); 00695 break; 00696 00697 case inside_simple_type: 00698 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00699 break; 00700 else 00701 ddx_fatal_error(parser, 00702 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.", 00703 localname); 00704 break; 00705 00706 case inside_array: 00707 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00708 break; 00709 else if (is_not(localname, "Array") 00710 && parser->is_variable(localname, attributes, nb_attributes)) 00711 break; 00712 else if (strcmp(localname, "dimension") == 0) { 00713 parser->process_dimension(attributes, nb_attributes); 00714 // next state: inside_dimension 00715 } 00716 else 00717 ddx_fatal_error(parser, 00718 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.", 00719 localname); 00720 break; 00721 00722 case inside_dimension: 00723 ddx_fatal_error(parser, 00724 "Internal parser error; unexpected state, inside dimension while processing element '%s'.", 00725 localname); 00726 break; 00727 00728 case inside_structure: 00729 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00730 break; 00731 else if (parser->is_variable(localname, attributes, nb_attributes)) 00732 break; 00733 else 00734 DDXParser::ddx_fatal_error(parser, 00735 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00736 localname); 00737 break; 00738 00739 case inside_sequence: 00740 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00741 break; 00742 else if (parser->is_variable(localname, attributes, nb_attributes)) 00743 break; 00744 else 00745 DDXParser::ddx_fatal_error(parser, 00746 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00747 localname); 00748 break; 00749 00750 case inside_grid: 00751 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00752 break; 00753 else if (strcmp(localname, "Array") == 0) 00754 parser->process_variable(dods_array_c, inside_array, attributes, nb_attributes); 00755 else if (strcmp(localname, "Map") == 0) 00756 parser->process_variable(dods_array_c, inside_map, attributes, nb_attributes); 00757 else 00758 DDXParser::ddx_fatal_error(parser, 00759 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00760 localname); 00761 break; 00762 00763 case inside_map: 00764 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00765 break; 00766 else if (is_not(localname, "Array") && is_not(localname, "Sequence") 00767 && is_not(localname, "Grid") 00768 && parser->is_variable(localname, attributes, nb_attributes)) 00769 break; 00770 else if (strcmp(localname, "dimension") == 0) { 00771 parser->process_dimension(attributes, nb_attributes); 00772 // next state: inside_dimension 00773 } 00774 else 00775 ddx_fatal_error(parser, 00776 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.", 00777 localname); 00778 break; 00779 00780 case inside_blob_href: 00781 ddx_fatal_error(parser, 00782 "Internal parser error; unexpected state, inside blob href while processing element '%s'.", 00783 localname); 00784 break; 00785 00786 case parser_unknown: 00787 // *** Never used? If so remove/error 00788 parser->set_state(parser_unknown); 00789 break; 00790 00791 case parser_error: 00792 break; 00793 } 00794 00795 DBGN(cerr << " ... " << states[parser->get_state()] << endl); 00796 } 00797 00798 void DDXParser::ddx_sax2_end_element(void *p, const xmlChar *l, 00799 const xmlChar *prefix, const xmlChar *URI) 00800 { 00801 DDXParser *parser = static_cast<DDXParser*>(p); 00802 const char *localname = (const char *)l; 00803 00804 DBG2(cerr << "End element " << localname << " (state " 00805 << states[parser->get_state()] << ")" << endl); 00806 00807 switch (parser->get_state()) { 00808 case parser_start: 00809 ddx_fatal_error(parser, 00810 "Internal parser error; unexpected state, inside start state while processing element '%s'.", 00811 localname); 00812 break; 00813 00814 case inside_dataset: 00815 if (strcmp(localname, "Dataset") == 0) 00816 parser->pop_state(); 00817 else 00818 DDXParser::ddx_fatal_error(parser, 00819 "Expected an end Dataset tag; found '%s' instead.", 00820 localname); 00821 break; 00822 00823 case inside_attribute_container: 00824 if (strcmp(localname, "Attribute") == 0) { 00825 parser->pop_state(); 00826 parser->at_stack.pop(); // pop when leaving a container. 00827 } 00828 else 00829 DDXParser::ddx_fatal_error(parser, 00830 "Expected an end Attribute tag; found '%s' instead.", 00831 localname); 00832 break; 00833 00834 case inside_attribute: 00835 if (strcmp(localname, "Attribute") == 0) 00836 parser->pop_state(); 00837 else 00838 DDXParser::ddx_fatal_error(parser, 00839 "Expected an end Attribute tag; found '%s' instead.", 00840 localname); 00841 break; 00842 00843 case inside_attribute_value: 00844 if (strcmp(localname, "value") == 0) { 00845 parser->pop_state(); 00846 AttrTable *atp = parser->at_stack.top(); 00847 atp->append_attr(parser->dods_attr_name, 00848 parser->dods_attr_type, parser->char_data); 00849 parser->char_data = ""; // Null this after use. 00850 } 00851 else 00852 DDXParser::ddx_fatal_error(parser, 00853 "Expected an end value tag; found '%s' instead.", 00854 localname); 00855 00856 break; 00857 00858 case inside_other_xml_attribute: { 00859 if (strcmp(localname, "Attribute") == 0 00860 && parser->root_ns == (const char *)URI) { 00861 00862 DBGN(cerr << endl << "\t Popping the 'inside_other_xml_attribute' state" 00863 << endl); 00864 00865 parser->pop_state(); 00866 00867 AttrTable *atp = parser->at_stack.top(); 00868 atp->append_attr(parser->dods_attr_name, 00869 parser->dods_attr_type, parser->other_xml); 00870 00871 parser->other_xml = ""; // Null this after use. 00872 } 00873 else { 00874 DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname 00875 << ", depth: " << parser->other_xml_depth << endl); 00876 if (parser->other_xml_depth == 0) 00877 DDXParser::ddx_fatal_error(parser, 00878 "Expected an OtherXML attribute to end! Instead I found '%s'", 00879 localname); 00880 parser->other_xml_depth--; 00881 00882 parser->other_xml.append("</"); 00883 if (prefix) { 00884 parser->other_xml.append((const char *)prefix); 00885 parser->other_xml.append(":"); 00886 } 00887 parser->other_xml.append(localname); 00888 parser->other_xml.append(">"); 00889 } 00890 break; 00891 } 00892 // Alias is busted in libdap++ 05/29/03 jhrg 00893 case inside_alias: 00894 parser->pop_state(); 00895 break; 00896 00897 case inside_simple_type: 00898 if (is_simple_type(localname) != dods_null_c) { 00899 parser->pop_state(); 00900 BaseType *btp = parser->bt_stack.top(); 00901 parser->bt_stack.pop(); 00902 parser->at_stack.pop(); 00903 00904 BaseType *parent = parser->bt_stack.top(); 00905 00906 if (parent->is_vector_type() || parent->is_constructor_type()) 00907 parent->add_var(btp); 00908 else 00909 DDXParser::ddx_fatal_error(parser, 00910 "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).", 00911 localname, 00912 parser->bt_stack.top()-> 00913 type_name().c_str(), 00914 parser->bt_stack.top()->name(). 00915 c_str()); 00916 } 00917 else 00918 DDXParser::ddx_fatal_error(parser, 00919 "Expected an end tag for a simple type; found '%s' instead.", 00920 localname); 00921 break; 00922 00923 case inside_array: 00924 parser->finish_variable(localname, dods_array_c, "Array"); 00925 break; 00926 00927 case inside_dimension: 00928 if (strcmp(localname, "dimension") == 0) 00929 parser->pop_state(); 00930 else 00931 DDXParser::ddx_fatal_error(parser, 00932 "Expected an end dimension tag; found '%s' instead.", 00933 localname); 00934 break; 00935 00936 case inside_structure: 00937 parser->finish_variable(localname, dods_structure_c, "Structure"); 00938 break; 00939 00940 case inside_sequence: 00941 parser->finish_variable(localname, dods_sequence_c, "Sequence"); 00942 break; 00943 00944 case inside_grid: 00945 parser->finish_variable(localname, dods_grid_c, "Grid"); 00946 break; 00947 00948 case inside_map: 00949 parser->finish_variable(localname, dods_array_c, "Map"); 00950 break; 00951 00952 case inside_blob_href: 00953 if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0) 00954 parser->pop_state(); 00955 else 00956 DDXParser::ddx_fatal_error(parser, 00957 "Expected an end dataBLOB/blob tag; found '%s' instead.", 00958 localname); 00959 break; 00960 00961 case parser_unknown: 00962 parser->pop_state(); 00963 break; 00964 00965 case parser_error: 00966 break; 00967 } 00968 00969 00970 DBGN(cerr << " ... " << states[parser->get_state()] << endl); 00971 } 00972 00976 void DDXParser::ddx_get_characters(void * p, const xmlChar * ch, int len) 00977 { 00978 DDXParser *parser = static_cast<DDXParser*>(p); 00979 00980 switch (parser->get_state()) { 00981 case inside_attribute_value: 00982 parser->char_data.append((const char *)(ch), len); 00983 DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl); 00984 break; 00985 00986 case inside_other_xml_attribute: 00987 parser->other_xml.append((const char *)(ch), len); 00988 DBG2(cerr << "Other XML Characters: '" << parser->other_xml << "'" << endl); 00989 break; 00990 00991 default: 00992 break; 00993 } 00994 } 00995 01000 void DDXParser::ddx_ignoreable_whitespace(void *p, const xmlChar *ch, 01001 int len) 01002 { 01003 DDXParser *parser = static_cast<DDXParser*>(p); 01004 01005 switch (parser->get_state()) { 01006 case inside_other_xml_attribute: 01007 parser->other_xml.append((const char *)(ch), len); 01008 break; 01009 01010 default: 01011 break; 01012 } 01013 } 01014 01020 void DDXParser::ddx_get_cdata(void *p, const xmlChar *value, int len) 01021 { 01022 DDXParser *parser = static_cast<DDXParser*>(p); 01023 01024 switch (parser->get_state()) { 01025 case inside_other_xml_attribute: 01026 parser->other_xml.append((const char *)(value), len); 01027 break; 01028 01029 case parser_unknown: 01030 break; 01031 01032 default: 01033 DDXParser::ddx_fatal_error(parser, 01034 "Found a CData block but none are allowed by DAP."); 01035 01036 break; 01037 } 01038 } 01039 01044 xmlEntityPtr DDXParser::ddx_get_entity(void *, const xmlChar * name) 01045 { 01046 return xmlGetPredefinedEntity(name); 01047 } 01048 01056 void DDXParser::ddx_fatal_error(void * p, const char *msg, ...) 01057 { 01058 va_list args; 01059 DDXParser *parser = static_cast<DDXParser*>(p); 01060 01061 parser->set_state(parser_error); 01062 01063 va_start(args, msg); 01064 char str[1024]; 01065 vsnprintf(str, 1024, msg, args); 01066 va_end(args); 01067 01068 int line = xmlSAX2GetLineNumber(parser->ctxt); 01069 01070 parser->error_msg += "At line " + long_to_string(line) + ": "; 01071 parser->error_msg += string(str) + string("\n"); 01072 } 01073 01075 01076 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context) const 01077 { 01078 if (!context->wellFormed) { 01079 context->sax = NULL; 01080 xmlFreeParserCtxt(context); 01081 throw 01082 DDXParseFailed(string 01083 ("\nThe DDX is not a well formed XML document.\n") 01084 + error_msg); 01085 } 01086 01087 if (!context->valid) { 01088 context->sax = NULL; 01089 xmlFreeParserCtxt(context); 01090 throw DDXParseFailed(string("\nThe DDX is not a valid document.\n") 01091 + error_msg); 01092 } 01093 01094 if (get_state() == parser_error) { 01095 context->sax = NULL; 01096 xmlFreeParserCtxt(context); 01097 throw DDXParseFailed(string("\nError parsing DDX response.\n") + 01098 error_msg); 01099 } 01100 01101 context->sax = NULL; 01102 xmlFreeParserCtxt(context); 01103 } 01104 01107 void DDXParser::intern_stream(FILE *in, DDS *dest_dds, string &cid, 01108 const string &boundary) 01109 { 01110 // Code example from libxml2 docs re: read from a stream. 01111 01112 if (!in || feof(in) || ferror(in)) 01113 throw InternalErr(__FILE__, __LINE__, 01114 "Input stream not open or read error"); 01115 01116 const int size = 1024; 01117 char chars[size]; 01118 01119 int res = fread(chars, 1, 4, in); 01120 if (res > 0) { 01121 xmlParserCtxtPtr context = 01122 xmlCreatePushParserCtxt(NULL, NULL, chars, res, "stream"); 01123 01124 ctxt = context; // need ctxt for error messages 01125 dds = dest_dds; // dump values here 01126 blob_href = &cid; // cid goes here 01127 01128 xmlSAXHandler ddx_sax_parser; 01129 memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) ); 01130 01131 ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity; 01132 ddx_sax_parser.startDocument = &DDXParser::ddx_start_document; 01133 ddx_sax_parser.endDocument = &DDXParser::ddx_end_document; 01134 ddx_sax_parser.characters = &DDXParser::ddx_get_characters; 01135 ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace; 01136 ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata; 01137 ddx_sax_parser.warning = &DDXParser::ddx_fatal_error; 01138 ddx_sax_parser.error = &DDXParser::ddx_fatal_error; 01139 ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error; 01140 ddx_sax_parser.initialized = XML_SAX2_MAGIC; 01141 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element; 01142 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element; 01143 01144 context->sax = &ddx_sax_parser; 01145 context->userData = this; 01146 context->validate = true; 01147 01148 while ((fgets(chars, size, in) > 0) && !is_boundary(chars, boundary)) { 01149 DBG(cerr << "line: " << chars << endl); 01150 xmlParseChunk(ctxt, chars, strlen(chars), 0); 01151 } 01152 // This call ends the parse: The fourth argument of xmlParseChunk is 01153 // the bool 'terminate.' 01154 xmlParseChunk(ctxt, chars, 0, 1); 01155 01156 cleanup_parse(context); 01157 } 01158 } 01159 01160 01172 void DDXParser::intern(const string & document, DDS * dest_dds, string &cid) 01173 { 01174 // Create the context pointer explicitly so that we can store a pointer 01175 // to it in the DDXParser instance. This provides a way to generate our 01176 // own error messages *with* line numbers. The messages are pretty 01177 // meaningless otherwise. This means that we use an interface from the 01178 // 'parser internals' header, and not the 'parser' header. However, this 01179 // interface is also used in one of the documented examples, so it's 01180 // probably pretty stable. 06/02/03 jhrg 01181 xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str()); 01182 if (!context) 01183 throw 01184 DDXParseFailed(string 01185 ("Could not initialize the parser with the file: '") 01186 + document + string("'.")); 01187 01188 dds = dest_dds; // dump values here 01189 blob_href = &cid; 01190 ctxt = context; // need ctxt for error messages 01191 01192 xmlSAXHandler ddx_sax_parser; 01193 memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) ); 01194 01195 ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity; 01196 ddx_sax_parser.startDocument = &DDXParser::ddx_start_document; 01197 ddx_sax_parser.endDocument = &DDXParser::ddx_end_document; 01198 ddx_sax_parser.characters = &DDXParser::ddx_get_characters; 01199 ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace; 01200 ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata; 01201 ddx_sax_parser.warning = &DDXParser::ddx_fatal_error; 01202 ddx_sax_parser.error = &DDXParser::ddx_fatal_error; 01203 ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error; 01204 ddx_sax_parser.initialized = XML_SAX2_MAGIC; 01205 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element; 01206 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element; 01207 01208 context->sax = &ddx_sax_parser; 01209 context->userData = this; 01210 context->validate = false; 01211 01212 xmlParseDocument(context); 01213 01214 cleanup_parse(context); 01215 } 01216 01217 } // namespace libdap