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