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 return; 00390 } 00391 00392 ap->append_dim(atoi(attribute_table["size"].value.c_str()), 00393 attribute_table["name"].value); 00394 } 00395 } 00396 00399 void DDXParser::process_blob(const xmlChar **attrs, int nb_attributes) 00400 { 00401 transfer_xml_attrs(attrs, nb_attributes); 00402 if (check_required_attribute(string("href"))) { 00403 set_state(inside_blob_href); 00404 *blob_href = attribute_table["href"].value; 00405 } 00406 } 00407 00414 inline bool 00415 DDXParser::is_attribute_or_alias(const char *name, const xmlChar **attrs, 00416 int nb_attributes) 00417 { 00418 if (strcmp(name, "Attribute") == 0) { 00419 process_attribute_element(attrs, nb_attributes); 00420 // next state: inside_attribtue or inside_attribute_container 00421 return true; 00422 } 00423 else if (strcmp(name, "Alias") == 0) { 00424 process_attribute_alias(attrs, nb_attributes); 00425 // next state: inside_alias 00426 return true; 00427 } 00428 00429 return false; 00430 } 00431 00437 inline bool DDXParser::is_variable(const char *name, const xmlChar **attrs, 00438 int nb_attributes) 00439 { 00440 Type t; 00441 if ((t = is_simple_type(name)) != dods_null_c) { 00442 process_variable(t, inside_simple_type, attrs, nb_attributes); 00443 return true; 00444 } 00445 else if (strcmp(name, "Array") == 0) { 00446 process_variable(dods_array_c, inside_array, attrs, nb_attributes); 00447 return true; 00448 } 00449 else if (strcmp(name, "Structure") == 0) { 00450 process_variable(dods_structure_c, inside_structure, attrs, nb_attributes); 00451 return true; 00452 } 00453 else if (strcmp(name, "Sequence") == 0) { 00454 process_variable(dods_sequence_c, inside_sequence, attrs, nb_attributes); 00455 return true; 00456 } 00457 else if (strcmp(name, "Grid") == 0) { 00458 process_variable(dods_grid_c, inside_grid, attrs, nb_attributes); 00459 return true; 00460 } 00461 00462 return false; 00463 } 00464 00465 void DDXParser::finish_variable(const char *tag, Type t, const char *expected) 00466 { 00467 if (strcmp(tag, expected) != 0) { 00468 DDXParser::ddx_fatal_error(this, 00469 "Expected an end tag for a %s; found '%s' instead.", 00470 expected, tag); 00471 return; 00472 } 00473 00474 pop_state(); 00475 00476 BaseType *btp = bt_stack.top(); 00477 00478 bt_stack.pop(); 00479 at_stack.pop(); 00480 00481 if (btp->type() != t) { 00482 DDXParser::ddx_fatal_error(this, 00483 "Internal error: Expected a %s variable.", 00484 expected); 00485 return; 00486 } 00487 // Once libxml2 validates, this can go away. 05/30/03 jhrg 00488 if (t == dods_array_c 00489 && dynamic_cast < Array * >(btp)->dimensions() == 0) { 00490 DDXParser::ddx_fatal_error(this, 00491 "No dimension element included in the Array '%s'.", 00492 btp->name().c_str()); 00493 return; 00494 } 00495 00496 BaseType *parent = bt_stack.top(); 00497 00498 if (!(parent->is_vector_type() || parent->is_constructor_type())) { 00499 DDXParser::ddx_fatal_error(this, 00500 "Tried to add the array variable '%s' to a non-constructor type (%s %s).", 00501 tag, 00502 bt_stack.top()->type_name().c_str(), 00503 bt_stack.top()->name().c_str()); 00504 return; 00505 } 00506 00507 parent->add_var(btp); 00508 } 00509 00516 00521 void DDXParser::ddx_start_document(void * p) 00522 { 00523 DDXParser *parser = static_cast<DDXParser*>(p); 00524 parser->error_msg = ""; 00525 parser->char_data = ""; 00526 00527 // init attr table stack. 00528 parser->at_stack.push(&parser->dds->get_attr_table()); 00529 00530 // Trick; DDS *should* be a child of Structure. To simplify parsing, 00531 // stuff a Structure on the bt_stack and dump the top level variables 00532 // there. Once we're done, transfer the variables to the DDS. 00533 parser->bt_stack.push(new Structure("dummy_dds")); 00534 00535 parser->set_state(parser_start); 00536 00537 DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl); 00538 } 00539 00542 void DDXParser::ddx_end_document(void * p) 00543 { 00544 DDXParser *parser = static_cast<DDXParser*>(p); 00545 DBG2(cerr << "Ending state == " << states[parser->get_state()] << 00546 endl); 00547 00548 if (parser->get_state() != parser_start) 00549 DDXParser::ddx_fatal_error(parser, 00550 "The document contained unbalanced tags."); 00551 00552 // If we've found any sort of error, don't make the DDX; intern() will 00553 // take care of the error. 00554 if (parser->get_state() == parser_error) 00555 return; 00556 00557 // Pop the temporary Structure off the stack and transfer its variables 00558 // to the DDS. 00559 Constructor *cp = dynamic_cast < Constructor * >(parser->bt_stack.top()); 00560 if (!cp) { 00561 ddx_fatal_error(parser, "Parse error: Expected a Structure, Sequence or Grid variable."); 00562 return; 00563 } 00564 00565 for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); 00566 ++i) 00567 parser->dds->add_var(*i); 00568 00569 parser->bt_stack.pop(); 00570 delete cp; 00571 } 00572 00573 void DDXParser::ddx_sax2_start_element(void *p, 00574 const xmlChar *l, const xmlChar *prefix, const xmlChar *URI, 00575 int nb_namespaces, const xmlChar **namespaces, 00576 int nb_attributes, int /*nb_defaulted*/, const xmlChar **attributes) 00577 { 00578 DDXParser *parser = static_cast<DDXParser*>(p); 00579 const char *localname = (const char *)l; 00580 00581 DBG2(cerr << "start element: " << localname << ", states: " 00582 << states[parser->get_state()]); 00583 00584 switch (parser->get_state()) { 00585 case parser_start: 00586 if (strcmp(localname, "Dataset") == 0) { 00587 parser->set_state(inside_dataset); 00588 parser->root_ns = URI != 0 ? (const char *)URI: ""; 00589 parser->transfer_xml_attrs(attributes, nb_attributes); 00590 00591 if (parser->check_required_attribute(string("name"))) 00592 parser->dds->set_dataset_name(parser->attribute_table["name"].value); 00593 00594 if (parser->check_attribute("dapVersion")) 00595 parser->dds->set_dap_version(parser->attribute_table["dapVersion"].value); 00596 } 00597 else 00598 DDXParser::ddx_fatal_error(parser, 00599 "Expected response to start with a Dataset element; found '%s' instead.", 00600 localname); 00601 break; 00602 00603 case inside_dataset: 00604 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00605 break; 00606 else if (parser->is_variable(localname, attributes, nb_attributes)) 00607 break; 00608 else if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0) { 00609 parser->process_blob(attributes, nb_attributes); 00610 // next state: inside_data_blob 00611 } 00612 else 00613 DDXParser::ddx_fatal_error(parser, 00614 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00615 localname); 00616 break; 00617 00618 case inside_attribute_container: 00619 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00620 break; 00621 else 00622 DDXParser::ddx_fatal_error(parser, 00623 "Expected an Attribute or Alias element; found '%s' instead.", 00624 localname); 00625 break; 00626 00627 case inside_attribute: 00628 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00629 break; 00630 else if (strcmp(localname, "value") == 0) 00631 parser->set_state(inside_attribute_value); 00632 else 00633 ddx_fatal_error(parser, 00634 "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.", 00635 localname); 00636 break; 00637 00638 case inside_attribute_value: 00639 ddx_fatal_error(parser, 00640 "Internal parser error; unexpected state, inside value while processing element '%s'.", 00641 localname); 00642 break; 00643 00644 case inside_other_xml_attribute: 00645 DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname << endl); 00646 00647 parser->other_xml_depth++; 00648 00649 // Accumulate the elements here 00650 00651 parser->other_xml.append("<"); 00652 if (prefix) { 00653 parser->other_xml.append((const char *)prefix); 00654 parser->other_xml.append(":"); 00655 } 00656 parser->other_xml.append(localname); 00657 00658 if (nb_namespaces != 0) { 00659 parser->transfer_xml_ns(namespaces, nb_namespaces); 00660 00661 for (map<string,string>::iterator i = parser->namespace_table.begin(); 00662 i != parser->namespace_table.end(); 00663 ++i) { 00664 parser->other_xml.append(" xmlns"); 00665 if (!i->first.empty()) { 00666 parser->other_xml.append(":"); 00667 parser->other_xml.append(i->first); 00668 } 00669 parser->other_xml.append("=\""); 00670 parser->other_xml.append(i->second); 00671 parser->other_xml.append("\""); 00672 } 00673 } 00674 00675 if (nb_attributes != 0) { 00676 parser->transfer_xml_attrs(attributes, nb_attributes); 00677 for (XMLAttrMap::iterator i = parser->attr_table_begin(); 00678 i != parser->attr_table_end(); 00679 ++i) { 00680 parser->other_xml.append(" "); 00681 if (!i->second.prefix.empty()) { 00682 parser->other_xml.append(i->second.prefix); 00683 parser->other_xml.append(":"); 00684 } 00685 parser->other_xml.append(i->first); 00686 parser->other_xml.append("=\""); 00687 parser->other_xml.append(i->second.value); 00688 parser->other_xml.append("\""); 00689 } 00690 } 00691 00692 parser->other_xml.append(">"); 00693 break; 00694 00695 case inside_alias: 00696 ddx_fatal_error(parser, 00697 "Internal parser error; unexpected state, inside alias while processing element '%s'.", 00698 localname); 00699 break; 00700 00701 case inside_simple_type: 00702 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00703 break; 00704 else 00705 ddx_fatal_error(parser, 00706 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.", 00707 localname); 00708 break; 00709 00710 case inside_array: 00711 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00712 break; 00713 else if (is_not(localname, "Array") 00714 && parser->is_variable(localname, attributes, nb_attributes)) 00715 break; 00716 else if (strcmp(localname, "dimension") == 0) { 00717 parser->process_dimension(attributes, nb_attributes); 00718 // next state: inside_dimension 00719 } 00720 else 00721 ddx_fatal_error(parser, 00722 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.", 00723 localname); 00724 break; 00725 00726 case inside_dimension: 00727 ddx_fatal_error(parser, 00728 "Internal parser error; unexpected state, inside dimension while processing element '%s'.", 00729 localname); 00730 break; 00731 00732 case inside_structure: 00733 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00734 break; 00735 else if (parser->is_variable(localname, attributes, nb_attributes)) 00736 break; 00737 else 00738 DDXParser::ddx_fatal_error(parser, 00739 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00740 localname); 00741 break; 00742 00743 case inside_sequence: 00744 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00745 break; 00746 else if (parser->is_variable(localname, attributes, nb_attributes)) 00747 break; 00748 else 00749 DDXParser::ddx_fatal_error(parser, 00750 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00751 localname); 00752 break; 00753 00754 case inside_grid: 00755 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00756 break; 00757 else if (strcmp(localname, "Array") == 0) 00758 parser->process_variable(dods_array_c, inside_array, attributes, nb_attributes); 00759 else if (strcmp(localname, "Map") == 0) 00760 parser->process_variable(dods_array_c, inside_map, attributes, nb_attributes); 00761 else 00762 DDXParser::ddx_fatal_error(parser, 00763 "Expected an Attribute, Alias or variable element; found '%s' instead.", 00764 localname); 00765 break; 00766 00767 case inside_map: 00768 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes)) 00769 break; 00770 else if (is_not(localname, "Array") && is_not(localname, "Sequence") 00771 && is_not(localname, "Grid") 00772 && parser->is_variable(localname, attributes, nb_attributes)) 00773 break; 00774 else if (strcmp(localname, "dimension") == 0) { 00775 parser->process_dimension(attributes, nb_attributes); 00776 // next state: inside_dimension 00777 } 00778 else 00779 ddx_fatal_error(parser, 00780 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.", 00781 localname); 00782 break; 00783 00784 case inside_blob_href: 00785 ddx_fatal_error(parser, 00786 "Internal parser error; unexpected state, inside blob href while processing element '%s'.", 00787 localname); 00788 break; 00789 00790 case parser_unknown: 00791 // *** Never used? If so remove/error 00792 parser->set_state(parser_unknown); 00793 break; 00794 00795 case parser_error: 00796 break; 00797 } 00798 00799 DBGN(cerr << " ... " << states[parser->get_state()] << endl); 00800 } 00801 00802 void DDXParser::ddx_sax2_end_element(void *p, const xmlChar *l, 00803 const xmlChar *prefix, const xmlChar *URI) 00804 { 00805 DDXParser *parser = static_cast<DDXParser*>(p); 00806 const char *localname = (const char *)l; 00807 00808 DBG2(cerr << "End element " << localname << " (state " 00809 << states[parser->get_state()] << ")" << endl); 00810 00811 switch (parser->get_state()) { 00812 case parser_start: 00813 ddx_fatal_error(parser, 00814 "Internal parser error; unexpected state, inside start state while processing element '%s'.", 00815 localname); 00816 break; 00817 00818 case inside_dataset: 00819 if (strcmp(localname, "Dataset") == 0) 00820 parser->pop_state(); 00821 else 00822 DDXParser::ddx_fatal_error(parser, 00823 "Expected an end Dataset tag; found '%s' instead.", 00824 localname); 00825 break; 00826 00827 case inside_attribute_container: 00828 if (strcmp(localname, "Attribute") == 0) { 00829 parser->pop_state(); 00830 parser->at_stack.pop(); // pop when leaving a container. 00831 } 00832 else 00833 DDXParser::ddx_fatal_error(parser, 00834 "Expected an end Attribute tag; found '%s' instead.", 00835 localname); 00836 break; 00837 00838 case inside_attribute: 00839 if (strcmp(localname, "Attribute") == 0) 00840 parser->pop_state(); 00841 else 00842 DDXParser::ddx_fatal_error(parser, 00843 "Expected an end Attribute tag; found '%s' instead.", 00844 localname); 00845 break; 00846 00847 case inside_attribute_value: 00848 if (strcmp(localname, "value") == 0) { 00849 parser->pop_state(); 00850 AttrTable *atp = parser->at_stack.top(); 00851 atp->append_attr(parser->dods_attr_name, 00852 parser->dods_attr_type, parser->char_data); 00853 parser->char_data = ""; // Null this after use. 00854 } 00855 else 00856 DDXParser::ddx_fatal_error(parser, 00857 "Expected an end value tag; found '%s' instead.", 00858 localname); 00859 00860 break; 00861 00862 case inside_other_xml_attribute: { 00863 if (strcmp(localname, "Attribute") == 0 00864 && parser->root_ns == (const char *)URI) { 00865 00866 DBGN(cerr << endl << "\t Popping the 'inside_other_xml_attribute' state" 00867 << endl); 00868 00869 parser->pop_state(); 00870 00871 AttrTable *atp = parser->at_stack.top(); 00872 atp->append_attr(parser->dods_attr_name, 00873 parser->dods_attr_type, parser->other_xml); 00874 00875 parser->other_xml = ""; // Null this after use. 00876 } 00877 else { 00878 DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname 00879 << ", depth: " << parser->other_xml_depth << endl); 00880 if (parser->other_xml_depth == 0) 00881 DDXParser::ddx_fatal_error(parser, 00882 "Expected an OtherXML attribute to end! Instead I found '%s'", 00883 localname); 00884 parser->other_xml_depth--; 00885 00886 parser->other_xml.append("</"); 00887 if (prefix) { 00888 parser->other_xml.append((const char *)prefix); 00889 parser->other_xml.append(":"); 00890 } 00891 parser->other_xml.append(localname); 00892 parser->other_xml.append(">"); 00893 } 00894 break; 00895 } 00896 // Alias is busted in libdap++ 05/29/03 jhrg 00897 case inside_alias: 00898 parser->pop_state(); 00899 break; 00900 00901 case inside_simple_type: 00902 if (is_simple_type(localname) != dods_null_c) { 00903 parser->pop_state(); 00904 BaseType *btp = parser->bt_stack.top(); 00905 parser->bt_stack.pop(); 00906 parser->at_stack.pop(); 00907 00908 BaseType *parent = parser->bt_stack.top(); 00909 00910 if (parent->is_vector_type() || parent->is_constructor_type()) 00911 parent->add_var(btp); 00912 else 00913 DDXParser::ddx_fatal_error(parser, 00914 "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).", 00915 localname, 00916 parser->bt_stack.top()-> 00917 type_name().c_str(), 00918 parser->bt_stack.top()->name(). 00919 c_str()); 00920 } 00921 else 00922 DDXParser::ddx_fatal_error(parser, 00923 "Expected an end tag for a simple type; found '%s' instead.", 00924 localname); 00925 break; 00926 00927 case inside_array: 00928 parser->finish_variable(localname, dods_array_c, "Array"); 00929 break; 00930 00931 case inside_dimension: 00932 if (strcmp(localname, "dimension") == 0) 00933 parser->pop_state(); 00934 else 00935 DDXParser::ddx_fatal_error(parser, 00936 "Expected an end dimension tag; found '%s' instead.", 00937 localname); 00938 break; 00939 00940 case inside_structure: 00941 parser->finish_variable(localname, dods_structure_c, "Structure"); 00942 break; 00943 00944 case inside_sequence: 00945 parser->finish_variable(localname, dods_sequence_c, "Sequence"); 00946 break; 00947 00948 case inside_grid: 00949 parser->finish_variable(localname, dods_grid_c, "Grid"); 00950 break; 00951 00952 case inside_map: 00953 parser->finish_variable(localname, dods_array_c, "Map"); 00954 break; 00955 00956 case inside_blob_href: 00957 if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0) 00958 parser->pop_state(); 00959 else 00960 DDXParser::ddx_fatal_error(parser, 00961 "Expected an end dataBLOB/blob tag; found '%s' instead.", 00962 localname); 00963 break; 00964 00965 case parser_unknown: 00966 parser->pop_state(); 00967 break; 00968 00969 case parser_error: 00970 break; 00971 } 00972 00973 00974 DBGN(cerr << " ... " << states[parser->get_state()] << endl); 00975 } 00976 00980 void DDXParser::ddx_get_characters(void * p, const xmlChar * ch, int len) 00981 { 00982 DDXParser *parser = static_cast<DDXParser*>(p); 00983 00984 switch (parser->get_state()) { 00985 case inside_attribute_value: 00986 parser->char_data.append((const char *)(ch), len); 00987 DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl); 00988 break; 00989 00990 case inside_other_xml_attribute: 00991 parser->other_xml.append((const char *)(ch), len); 00992 DBG2(cerr << "Other XML Characters: '" << parser->other_xml << "'" << endl); 00993 break; 00994 00995 default: 00996 break; 00997 } 00998 } 00999 01004 void DDXParser::ddx_ignoreable_whitespace(void *p, const xmlChar *ch, 01005 int len) 01006 { 01007 DDXParser *parser = static_cast<DDXParser*>(p); 01008 01009 switch (parser->get_state()) { 01010 case inside_other_xml_attribute: 01011 parser->other_xml.append((const char *)(ch), len); 01012 break; 01013 01014 default: 01015 break; 01016 } 01017 } 01018 01024 void DDXParser::ddx_get_cdata(void *p, const xmlChar *value, int len) 01025 { 01026 DDXParser *parser = static_cast<DDXParser*>(p); 01027 01028 switch (parser->get_state()) { 01029 case inside_other_xml_attribute: 01030 parser->other_xml.append((const char *)(value), len); 01031 break; 01032 01033 case parser_unknown: 01034 break; 01035 01036 default: 01037 DDXParser::ddx_fatal_error(parser, 01038 "Found a CData block but none are allowed by DAP."); 01039 01040 break; 01041 } 01042 } 01043 01048 xmlEntityPtr DDXParser::ddx_get_entity(void *, const xmlChar * name) 01049 { 01050 return xmlGetPredefinedEntity(name); 01051 } 01052 01060 void DDXParser::ddx_fatal_error(void * p, const char *msg, ...) 01061 { 01062 va_list args; 01063 DDXParser *parser = static_cast<DDXParser*>(p); 01064 01065 parser->set_state(parser_error); 01066 01067 va_start(args, msg); 01068 char str[1024]; 01069 vsnprintf(str, 1024, msg, args); 01070 va_end(args); 01071 01072 int line = xmlSAX2GetLineNumber(parser->ctxt); 01073 01074 parser->error_msg += "At line " + long_to_string(line) + ": "; 01075 parser->error_msg += string(str) + string("\n"); 01076 } 01077 01079 01080 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context) const 01081 { 01082 if (!context->wellFormed) { 01083 context->sax = NULL; 01084 xmlFreeParserCtxt(context); 01085 throw 01086 DDXParseFailed(string 01087 ("\nThe DDX is not a well formed XML document.\n") 01088 + error_msg); 01089 } 01090 01091 if (!context->valid) { 01092 context->sax = NULL; 01093 xmlFreeParserCtxt(context); 01094 throw DDXParseFailed(string("\nThe DDX is not a valid document.\n") 01095 + error_msg); 01096 } 01097 01098 if (get_state() == parser_error) { 01099 context->sax = NULL; 01100 xmlFreeParserCtxt(context); 01101 throw DDXParseFailed(string("\nError parsing DDX response.\n") + 01102 error_msg); 01103 } 01104 01105 context->sax = NULL; 01106 xmlFreeParserCtxt(context); 01107 } 01108 01111 void DDXParser::intern_stream(FILE *in, DDS *dest_dds, string &cid, 01112 const string &boundary) 01113 { 01114 // Code example from libxml2 docs re: read from a stream. 01115 01116 if (!in || feof(in) || ferror(in)) 01117 throw InternalErr(__FILE__, __LINE__, 01118 "Input stream not open or read error"); 01119 01120 const int size = 1024; 01121 char chars[size]; 01122 01123 int res = fread(chars, 1, 4, in); 01124 if (res > 0) { 01125 xmlParserCtxtPtr context = 01126 xmlCreatePushParserCtxt(NULL, NULL, chars, res, "stream"); 01127 01128 ctxt = context; // need ctxt for error messages 01129 dds = dest_dds; // dump values here 01130 blob_href = &cid; // cid goes here 01131 01132 xmlSAXHandler ddx_sax_parser; 01133 memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) ); 01134 01135 ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity; 01136 ddx_sax_parser.startDocument = &DDXParser::ddx_start_document; 01137 ddx_sax_parser.endDocument = &DDXParser::ddx_end_document; 01138 ddx_sax_parser.characters = &DDXParser::ddx_get_characters; 01139 ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace; 01140 ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata; 01141 ddx_sax_parser.warning = &DDXParser::ddx_fatal_error; 01142 ddx_sax_parser.error = &DDXParser::ddx_fatal_error; 01143 ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error; 01144 ddx_sax_parser.initialized = XML_SAX2_MAGIC; 01145 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element; 01146 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element; 01147 01148 context->sax = &ddx_sax_parser; 01149 context->userData = this; 01150 context->validate = true; 01151 01152 01153 while ((fgets(chars, size, in) > 0) && !is_boundary(chars, boundary)) { 01154 chars[size-1] = '\0'; 01155 DBG(cerr << "line: " << chars << endl); 01156 xmlParseChunk(ctxt, chars, strlen(chars), 0); 01157 } 01158 // This call ends the parse: The fourth argument of xmlParseChunk is 01159 // the bool 'terminate.' 01160 xmlParseChunk(ctxt, chars, 0, 1); 01161 01162 cleanup_parse(context); 01163 } 01164 } 01165 01166 01178 void DDXParser::intern(const string & document, DDS * dest_dds, string &cid) 01179 { 01180 // Create the context pointer explicitly so that we can store a pointer 01181 // to it in the DDXParser instance. This provides a way to generate our 01182 // own error messages *with* line numbers. The messages are pretty 01183 // meaningless otherwise. This means that we use an interface from the 01184 // 'parser internals' header, and not the 'parser' header. However, this 01185 // interface is also used in one of the documented examples, so it's 01186 // probably pretty stable. 06/02/03 jhrg 01187 xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str()); 01188 if (!context) 01189 throw 01190 DDXParseFailed(string 01191 ("Could not initialize the parser with the file: '") 01192 + document + string("'.")); 01193 01194 dds = dest_dds; // dump values here 01195 blob_href = &cid; 01196 ctxt = context; // need ctxt for error messages 01197 01198 xmlSAXHandler ddx_sax_parser; 01199 memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) ); 01200 01201 ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity; 01202 ddx_sax_parser.startDocument = &DDXParser::ddx_start_document; 01203 ddx_sax_parser.endDocument = &DDXParser::ddx_end_document; 01204 ddx_sax_parser.characters = &DDXParser::ddx_get_characters; 01205 ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace; 01206 ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata; 01207 ddx_sax_parser.warning = &DDXParser::ddx_fatal_error; 01208 ddx_sax_parser.error = &DDXParser::ddx_fatal_error; 01209 ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error; 01210 ddx_sax_parser.initialized = XML_SAX2_MAGIC; 01211 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element; 01212 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element; 01213 01214 context->sax = &ddx_sax_parser; 01215 context->userData = this; 01216 context->validate = false; 01217 01218 xmlParseDocument(context); 01219 01220 cleanup_parse(context); 01221 } 01222 01223 } // namespace libdap