libdap++
Updated for version 3.8.2
|
00001 // -*- mode: c++; c-basic-offset:4 -*- 00002 00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00004 // Access Protocol. 00005 00006 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00007 // Author: James Gallagher <jgallagher@opendap.org> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00024 00025 // (c) COPYRIGHT URI/MIT 1994-1999 00026 // Please read the full copyright statement in the file COPYRIGHT_URI. 00027 // 00028 // Authors: 00029 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00030 00031 // 00032 // jhrg 9/7/94 00033 00034 #include "config.h" 00035 00036 static char rcsid[] not_used = 00037 {"$Id: DDS.cc 25066 2011-11-30 18:39:37Z jimg $" 00038 }; 00039 00040 #include <cstdio> 00041 #include <sys/types.h> 00042 00043 #ifdef WIN32 00044 #include <io.h> 00045 #include <process.h> 00046 #include <fstream> 00047 #else 00048 #include <unistd.h> // for alarm and dup 00049 #include <sys/wait.h> 00050 #endif 00051 00052 #include <iostream> 00053 #include <sstream> 00054 #include <algorithm> 00055 #include <functional> 00056 00057 //#define DODS_DEBUG 00058 //#define DODS_DEBUG2 00059 00060 #include "GNURegex.h" 00061 00062 #include "DAS.h" 00063 #include "Clause.h" 00064 #include "Error.h" 00065 #include "InternalErr.h" 00066 #include "Keywords2.h" 00067 00068 #include "parser.h" 00069 #include "debug.h" 00070 #include "util.h" 00071 00072 #include "Byte.h" 00073 #include "Int16.h" 00074 #include "UInt16.h" 00075 #include "Int32.h" 00076 #include "UInt32.h" 00077 #include "Float32.h" 00078 #include "Float64.h" 00079 #include "Str.h" 00080 #include "Url.h" 00081 #include "Array.h" 00082 #include "Structure.h" 00083 #include "Sequence.h" 00084 #include "Grid.h" 00085 00086 #include "escaping.h" 00087 00088 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd"; 00089 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd"; 00090 00091 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2"; 00092 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#"; 00093 00094 const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location; 00095 const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location; 00096 00097 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl"; 00098 00099 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace"; 00100 00101 using namespace std; 00102 00103 void ddsrestart(FILE *yyin); // Defined in dds.tab.c 00104 int ddsparse(void *arg); 00105 00106 // Glue for the DDS parser defined in dds.lex 00107 void dds_switch_to_buffer(void *new_buffer); 00108 void dds_delete_buffer(void * buffer); 00109 void *dds_buffer(FILE *fp); 00110 00111 namespace libdap { 00112 00113 void 00114 DDS::duplicate(const DDS &dds) 00115 { 00116 DBG(cerr << "Entering DDS::duplicate... " <<endl); 00117 name = dds.name; 00118 d_filename = dds.d_filename; 00119 d_container_name = dds.d_container_name; 00120 d_timeout = dds.d_timeout; 00121 d_attr = dds.d_attr; 00122 00123 d_factory = dds.d_factory; 00124 d_container = dds.d_container; 00125 d_dap_major = dds.d_dap_major; 00126 d_dap_minor = dds.d_dap_minor; 00127 00128 d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers 00129 00130 DDS &dds_tmp = const_cast<DDS &>(dds); 00131 00132 // copy the things pointed to by the list, not just the pointers 00133 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) { 00134 add_var(*i); // add_var() dups the BaseType. 00135 } 00136 } 00137 00148 DDS::DDS(BaseTypeFactory *factory, const string &n) 00149 : d_factory(factory), name(n), d_container(0), 00150 d_dap_major(2), d_dap_minor(0), 00151 d_request_xml_base(""), d_timeout(0), d_keywords(), 00152 d_max_response_size(0) 00153 { 00154 DBG(cerr << "Building a DDS with client major/minor: " 00155 << d_dap_major << "." << d_dap_minor << endl); 00156 } 00157 00159 DDS::DDS(const DDS &rhs) : DapObj() 00160 { 00161 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl); 00162 duplicate(rhs); 00163 DBG(cerr << " bye." << endl); 00164 } 00165 00166 DDS::~DDS() 00167 { 00168 // delete all the variables in this DDS 00169 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00170 BaseType *btp = *i ; 00171 delete btp ; btp = 0; 00172 } 00173 } 00174 00175 DDS & 00176 DDS::operator=(const DDS &rhs) 00177 { 00178 DBG(cerr << "Entering DDS::operator= ..." << endl); 00179 if (this == &rhs) 00180 return *this; 00181 00182 duplicate(rhs); 00183 00184 DBG(cerr << " bye." << endl); 00185 return *this; 00186 } 00187 00201 void DDS::transfer_attributes(DAS *das) { 00202 // If there is a container set in the DDS then get the container from 00203 // the DAS. If they are not the same container, then throw an exception 00204 // (should be working on the same container). If the container does not 00205 // exist in the DAS, then throw an exception 00206 if (d_container) { 00207 if (das->container_name() != d_container_name) 00208 throw InternalErr(__FILE__, __LINE__, 00209 "Error transferring attributes: working on a container in dds, but not das"); 00210 } 00211 00212 // Give each variable a chance to claim its attributes. 00213 AttrTable *top_level = das->get_top_level_attributes(); 00214 00215 Vars_iter var = var_begin(); 00216 while (var != var_end()) { 00217 try { 00218 DBG(cerr << "Processing the attributes for: " << (*var)->name() << " a " << (*var)->type_name() << endl); 00219 (*var)->transfer_attributes(top_level); 00220 var++; 00221 } catch (Error &e) { 00222 DBG(cerr << "Got this exception: " << e.get_error_message() << endl); 00223 var++; 00224 throw e; 00225 } 00226 } 00227 00228 // Now we transfer all of the attributes still marked as global to the 00229 // global container in the DDS. 00230 00231 AttrTable::Attr_iter at_cont_p = top_level->attr_begin(); 00232 while (at_cont_p != top_level->attr_end()) { 00233 // In truth, all of the top level attributes should be containers, but 00234 // this test handles the abnormal case where somehow someone makes a 00235 // top level attribute that is not a container by silently dropping it. 00236 if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) { 00237 DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl); 00238 // copy the source container so that the DAS passed in can be 00239 // deleted after calling this method. 00240 AttrTable *at = new AttrTable(*(*at_cont_p)->attributes); 00241 d_attr.append_container(at, at->get_name()); 00242 } 00243 00244 at_cont_p++; 00245 } 00246 } 00247 00255 00257 string 00258 DDS::get_dataset_name() const 00259 { 00260 return name; 00261 } 00262 00264 void 00265 DDS::set_dataset_name(const string &n) 00266 { 00267 name = n; 00268 } 00269 00271 00273 AttrTable & 00274 DDS::get_attr_table() 00275 { 00276 return d_attr; 00277 } 00278 00288 string 00289 DDS::filename() 00290 { 00291 return d_filename; 00292 } 00293 00295 void 00296 DDS::filename(const string &fn) 00297 { 00298 d_filename = fn; 00299 } 00301 00302 void 00303 DDS::set_dap_major(int p) 00304 { 00305 d_dap_major = p; 00306 00307 // This works because regardless of the order set_dap_major and set_dap_minor 00308 // are called, once they both are called, the value in the string is 00309 // correct. I protect against negative numbers because that would be 00310 // nonsensical. 00311 if (d_dap_minor >= 0) { 00312 ostringstream oss; 00313 oss << d_dap_major << "." << d_dap_minor; 00314 d_dap_version = oss.str(); 00315 } 00316 } 00317 00318 void 00319 DDS::set_dap_minor(int p) 00320 { 00321 d_dap_minor = p; 00322 00323 if (d_dap_major >= 0) { 00324 ostringstream oss; 00325 oss << d_dap_major << "." << d_dap_minor; 00326 d_dap_version = oss.str(); 00327 } 00328 } 00329 00336 void 00337 DDS::set_dap_version(const string &version_string) 00338 { 00339 istringstream iss(version_string); 00340 00341 int major = -1, minor = -1; 00342 char dot; 00343 if (!iss.eof() && !iss.fail()) 00344 iss >> major; 00345 if (!iss.eof() && !iss.fail()) 00346 iss >> dot; 00347 if (!iss.eof() && !iss.fail()) 00348 iss >> minor; 00349 00350 DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl); 00351 #if 0 00352 if (major == -1 || minor == -1) 00353 throw Error("Could not parse the client dap (XDAP-Accept header) value"); 00354 #endif 00355 00356 d_dap_version = version_string; 00357 00358 set_dap_major(major == -1 ? 2 : major); 00359 set_dap_minor(minor == -1 ? 0 : minor); 00360 } 00361 00369 void 00370 DDS::set_dap_version(double d) 00371 { 00372 int major = d; 00373 int minor = (d-major)*10; 00374 00375 DBG(cerr << "Major: " << major << ", Minor: " << minor << endl); 00376 00377 ostringstream oss; 00378 oss << major << "." << minor; 00379 d_dap_version = oss.str(); 00380 00381 set_dap_major(major); 00382 set_dap_minor(minor); 00383 } 00384 00394 string 00395 DDS::container_name() 00396 { 00397 return d_container_name; 00398 } 00399 00402 void 00403 DDS::container_name(const string &cn) 00404 { 00405 // we want to search the DDS for the top level structure with the given 00406 // name. Set the container to null so that we don't search some previous 00407 // container. 00408 d_container = 0 ; 00409 if( !cn.empty() ) 00410 { 00411 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00412 if( !d_container ) 00413 { 00414 // create a structure for this container. Calling add_var 00415 // while_container is null will add the new structure to DDS and 00416 // not some sub structure. Adding the new structure makes a copy 00417 // of it. So after adding it, go get it and set d_container. 00418 Structure *s = new Structure( cn ) ; 00419 add_var( s ) ; 00420 delete s ; 00421 s = 0 ; 00422 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00423 } 00424 } 00425 d_container_name = cn; 00426 00427 } 00428 00430 Structure * 00431 DDS::container() 00432 { 00433 return d_container ; 00434 } 00435 00437 00448 int 00449 DDS::get_request_size(bool constrained) 00450 { 00451 int w = 0; 00452 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00453 if (constrained) { 00454 if ((*i)->send_p()) 00455 w += (*i)->width(constrained); 00456 } 00457 else { 00458 w += (*i)->width(constrained); 00459 } 00460 } 00461 00462 return w; 00463 } 00464 00470 void DDS::add_var(BaseType *bt) { 00471 if (!bt) 00472 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer."); 00473 00474 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl); 00475 00476 BaseType *btp = bt->ptr_duplicate(); 00477 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl); 00478 if (d_container) { 00479 // Mem leak fix [mjohnson nov 2009] 00480 // Structure::add_var() creates ANOTHER copy. 00481 d_container->add_var(bt); 00482 // So we need to delete btp or else it leaks 00483 delete btp; 00484 btp = 0; 00485 } 00486 else { 00487 vars.push_back(btp); 00488 } 00489 } 00490 00493 void DDS::add_var_nocopy(BaseType *bt) { 00494 if (!bt) 00495 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer."); 00496 00497 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl); 00498 00499 BaseType *btp = bt->ptr_duplicate(); 00500 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl); 00501 if (d_container) { 00502 // Mem leak fix [mjohnson nov 2009] 00503 // Structure::add_var() creates ANOTHER copy. 00504 d_container->add_var(bt); 00505 // So we need to delete btp or else it leaks 00506 delete btp; 00507 btp = 0; 00508 } 00509 else { 00510 vars.push_back(btp); 00511 } 00512 } 00513 00514 00521 void 00522 DDS::del_var(const string &n) 00523 { 00524 if( d_container ) 00525 { 00526 d_container->del_var( n ) ; 00527 return ; 00528 } 00529 00530 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00531 if ((*i)->name() == n) { 00532 BaseType *bt = *i ; 00533 vars.erase(i) ; 00534 delete bt ; bt = 0; 00535 return; 00536 } 00537 } 00538 } 00539 00544 void 00545 DDS::del_var(Vars_iter i) 00546 { 00547 if (i != vars.end()) { 00548 BaseType *bt = *i ; 00549 vars.erase(i) ; 00550 delete bt ; bt = 0; 00551 } 00552 } 00553 00560 void 00561 DDS::del_var(Vars_iter i1, Vars_iter i2) 00562 { 00563 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) { 00564 BaseType *bt = *i_tmp ; 00565 delete bt ; bt = 0; 00566 } 00567 vars.erase(i1, i2) ; 00568 } 00569 00577 BaseType * 00578 DDS::var(const string &n, BaseType::btp_stack &s) 00579 { 00580 return var(n, &s); 00581 } 00601 BaseType * 00602 DDS::var(const string &n, BaseType::btp_stack *s) 00603 { 00604 string name = www2id(n); 00605 if( d_container ) 00606 return d_container->var( name, false, s ) ; 00607 00608 BaseType *v = exact_match(name, s); 00609 if (v) 00610 return v; 00611 00612 return leaf_match(name, s); 00613 } 00614 00615 BaseType * 00616 DDS::leaf_match(const string &n, BaseType::btp_stack *s) 00617 { 00618 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl); 00619 00620 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00621 BaseType *btp = *i; 00622 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl); 00623 // Look for the name in the dataset's top-level 00624 if (btp->name() == n) { 00625 DBG(cerr << "Found " << n << " in: " << btp->name() << endl); 00626 return btp; 00627 } 00628 00629 if (btp->is_constructor_type()) { 00630 BaseType *found = btp->var(n, false, s); 00631 if (found) { 00632 DBG(cerr << "Found " << n << " in: " << btp->name() << endl); 00633 return found; 00634 } 00635 } 00636 #if STRUCTURE_ARRAY_SYNTAX_OLD 00637 if (btp->is_vector_type() && btp->var()->is_constructor_type()) { 00638 s->push(btp); 00639 BaseType *found = btp->var()->var(n, false, s); 00640 if (found) { 00641 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl); 00642 return found; 00643 } 00644 } 00645 #endif 00646 } 00647 00648 return 0; // It is not here. 00649 } 00650 00651 BaseType * 00652 DDS::exact_match(const string &name, BaseType::btp_stack *s) 00653 { 00654 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00655 BaseType *btp = *i; 00656 DBG2(cerr << "Looking for " << name << " in: " << btp << endl); 00657 // Look for the name in the current ctor type or the top level 00658 if (btp->name() == name) { 00659 DBG2(cerr << "Found " << name << " in: " << btp << endl); 00660 return btp; 00661 } 00662 } 00663 00664 string::size_type dot_pos = name.find("."); 00665 if (dot_pos != string::npos) { 00666 string aggregate = name.substr(0, dot_pos); 00667 string field = name.substr(dot_pos + 1); 00668 00669 BaseType *agg_ptr = var(aggregate, s); 00670 if (agg_ptr) { 00671 DBG2(cerr << "Descending into " << agg_ptr->name() << endl); 00672 return agg_ptr->var(field, true, s); 00673 } 00674 else 00675 return 0; // qualified names must be *fully* qualified 00676 } 00677 00678 return 0; // It is not here. 00679 } 00680 00681 00684 DDS::Vars_iter 00685 DDS::var_begin() 00686 { 00687 return vars.begin(); 00688 } 00689 00690 DDS::Vars_riter 00691 DDS::var_rbegin() 00692 { 00693 return vars.rbegin(); 00694 } 00695 00696 DDS::Vars_iter 00697 DDS::var_end() 00698 { 00699 return vars.end() ; 00700 } 00701 00702 DDS::Vars_riter 00703 DDS::var_rend() 00704 { 00705 return vars.rend() ; 00706 } 00707 00711 DDS::Vars_iter 00712 DDS::get_vars_iter(int i) 00713 { 00714 return vars.begin() + i; 00715 } 00716 00720 BaseType * 00721 DDS::get_var_index(int i) 00722 { 00723 return *(vars.begin() + i); 00724 } 00725 00730 void 00731 DDS::insert_var(Vars_iter i, BaseType *ptr) 00732 { 00733 vars.insert(i, ptr->ptr_duplicate()); 00734 } 00735 00743 void 00744 DDS::insert_var_nocopy(Vars_iter i, BaseType *ptr) 00745 { 00746 vars.insert(i, ptr); 00747 } 00748 00750 int 00751 DDS::num_var() 00752 { 00753 return vars.size(); 00754 } 00755 00756 void 00757 DDS::timeout_on() 00758 { 00759 #ifndef WIN32 00760 alarm(d_timeout); 00761 #endif 00762 } 00763 00764 void 00765 DDS::timeout_off() 00766 { 00767 #ifndef WIN32 00768 d_timeout = alarm(0); 00769 #endif 00770 } 00771 00772 void 00773 DDS::set_timeout(int t) 00774 { 00775 // Has no effect under win32 00776 d_timeout = t; 00777 } 00778 00779 int 00780 DDS::get_timeout() 00781 { 00782 // Has to effect under win32 00783 return d_timeout; 00784 } 00785 00787 void 00788 DDS::tag_nested_sequences() 00789 { 00790 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00791 if ((*i)->type() == dods_sequence_c) 00792 dynamic_cast<Sequence&>(**i).set_leaf_sequence(); 00793 else if ((*i)->type() == dods_structure_c) 00794 dynamic_cast<Structure&>(**i).set_leaf_sequence(); 00795 } 00796 } 00797 00799 void 00800 DDS::parse(string fname) 00801 { 00802 FILE *in = fopen(fname.c_str(), "r"); 00803 00804 if (!in) { 00805 throw Error(cannot_read_file, "Could not open: " + fname); 00806 } 00807 00808 try { 00809 parse(in); 00810 fclose(in); 00811 } 00812 catch (Error &e) { 00813 fclose(in); 00814 throw ; 00815 } 00816 } 00817 00818 00820 void 00821 DDS::parse(int fd) 00822 { 00823 #ifdef WIN32 00824 FILE *in = fdopen(_dup(fd), "r"); 00825 #else 00826 FILE *in = fdopen(dup(fd), "r"); 00827 #endif 00828 00829 if (!in) { 00830 throw InternalErr(__FILE__, __LINE__, "Could not access file."); 00831 } 00832 00833 try { 00834 parse(in); 00835 fclose(in); 00836 } 00837 catch (Error &e) { 00838 fclose(in); 00839 throw ; 00840 } 00841 } 00842 00849 void 00850 DDS::parse(FILE *in) 00851 { 00852 if (!in) { 00853 throw InternalErr(__FILE__, __LINE__, "Null input stream."); 00854 } 00855 00856 void *buffer = dds_buffer(in); 00857 dds_switch_to_buffer(buffer); 00858 00859 parser_arg arg(this); 00860 00861 bool status = ddsparse((void *) & arg) == 0; 00862 00863 dds_delete_buffer(buffer); 00864 00865 DBG2(cout << "Status from parser: " << status << endl); 00866 00867 // STATUS is the result of the parser function; if a recoverable error 00868 // was found it will be true but arg.status() will be false. 00869 if (!status || !arg.status()) {// Check parse result 00870 if (arg.error()) 00871 throw *arg.error(); 00872 } 00873 } 00874 00875 #if FILE_METHODS 00876 00877 void 00878 DDS::print(FILE *out) 00879 { 00880 #if 0 00881 ostringstream oss; 00882 print(oss); 00883 00884 fwrite(oss.str().c_str(), oss.str().length(), 1, out); 00885 #else 00886 fprintf(out, "Dataset {\n") ; 00887 00888 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00889 (*i)->print_decl(out) ; 00890 } 00891 00892 fprintf(out, "} %s;\n", id2www(name).c_str()) ; 00893 00894 return ; 00895 #endif 00896 } 00897 #endif 00898 00900 void 00901 DDS::print(ostream &out) 00902 { 00903 out << "Dataset {\n" ; 00904 00905 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00906 (*i)->print_decl(out) ; 00907 } 00908 00909 out << "} " << id2www(name) << ";\n" ; 00910 00911 return ; 00912 } 00913 00914 #if FILE_METHODS 00915 00925 void 00926 DDS::print_constrained(FILE *out) 00927 { 00928 fprintf(out, "Dataset {\n") ; 00929 00930 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00931 // for each variable, indent with four spaces, print a trailing 00932 // semicolon, do not print debugging information, print only 00933 // variables in the current projection. 00934 (*i)->print_decl(out, " ", true, false, true) ; 00935 } 00936 00937 fprintf(out, "} %s;\n", id2www(name).c_str()) ; 00938 00939 return; 00940 } 00941 #endif 00942 00953 void 00954 DDS::print_constrained(ostream &out) 00955 { 00956 out << "Dataset {\n" ; 00957 00958 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00959 // for each variable, indent with four spaces, print a trailing 00960 // semicolon, do not print debugging information, print only 00961 // variables in the current projection. 00962 (*i)->print_decl(out, " ", true, false, true) ; 00963 } 00964 00965 out << "} " << id2www(name) << ";\n" ; 00966 00967 return; 00968 } 00969 00970 #if FILE_METHODS 00971 class VariablePrintXML : public unary_function<BaseType *, void> 00972 { 00973 FILE *d_out; 00974 bool d_constrained; 00975 public: 00976 VariablePrintXML(FILE *out, bool constrained) 00977 : d_out(out), d_constrained(constrained) 00978 {} 00979 void operator()(BaseType *bt) 00980 { 00981 bt->print_xml(d_out, " ", d_constrained); 00982 } 00983 }; 00984 00996 void 00997 DDS::print_xml(FILE *out, bool constrained, const string &blob) 00998 { 00999 ostringstream oss; 01000 print_xml_writer(oss, constrained, blob); 01001 01002 string doc = oss.str(); 01003 fwrite(doc.data(), 1, doc.length(), out); 01004 01005 #if 0 01006 fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 01007 01008 fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str()); 01009 01010 fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); 01011 01012 fprintf(out,"method=\"FILE*\"\n"); 01013 fprintf(out, "dap_major=\"%d\"\n", get_dap_major()); 01014 fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor()); 01015 01016 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 01017 // this at some point... jhrg 01018 if (get_dap_major() == 3 && get_dap_minor() == 2) { 01019 fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str()); 01020 01021 fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n", 01022 c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str()); 01023 } 01024 else { 01025 fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str()); 01026 fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n", 01027 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str()); 01028 } 01029 01030 01031 d_attr.print_xml(out, " ", constrained); 01032 01033 fprintf(out, "\n"); 01034 01035 for_each(var_begin(), var_end(), VariablePrintXML(out, constrained)); 01036 01037 fprintf(out, "\n"); 01038 01039 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 01040 // the same. jhrg 01041 if (get_dap_major() == 2 && get_dap_minor() == 0) { 01042 fprintf(out, " <dataBLOB href=\"\"/>\n"); 01043 } 01044 else if (!blob.empty() 01045 && (get_dap_major() == 3 && get_dap_minor() >= 2) 01046 || get_dap_major() >= 4) { 01047 fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str()); 01048 } 01049 01050 01051 fprintf(out, "</Dataset>\n"); 01052 #endif 01053 } 01054 #endif 01055 01056 class VariablePrintXMLStrm : public unary_function<BaseType *, void> 01057 { 01058 ostream &d_out; 01059 bool d_constrained; 01060 public: 01061 VariablePrintXMLStrm(ostream &out, bool constrained) 01062 : d_out(out), d_constrained(constrained) 01063 {} 01064 void operator()(BaseType *bt) 01065 { 01066 bt->print_xml(d_out, " ", d_constrained); 01067 } 01068 }; 01069 01081 void 01082 DDS::print_xml(ostream &out, bool constrained, const string &blob) 01083 { 01084 print_xml_writer(out, constrained, blob); 01085 01086 #if 0 01087 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ; 01088 01089 out << "<Dataset name=\"" << id2xml(name) << "\"\n" ; 01090 01091 out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ; 01092 01093 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 01094 // this at some point... jhrg 01095 if (get_dap_major() == 3 && get_dap_minor() == 2) { 01096 out << "xsi:schemaLocation=\"" << c_dap32_namespace 01097 << " " << c_default_dap32_schema_location << "\"\n" ; 01098 01099 out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n"; 01100 out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n"; 01101 01102 out << "xmlns=\"" << c_dap32_namespace << "\"\n" ; 01103 out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ; 01104 01105 out << "dapVersion=\"" << get_dap_major() << "." 01106 << get_dap_minor() << "\""; 01107 01108 if (!get_request_xml_base().empty()) { 01109 out << "\n"; 01110 out << "xmlns:xml=\"" << c_xml_namespace << "\"\n"; 01111 out << "xml:base=\"" << get_request_xml_base() << "\""; 01112 } 01113 01114 // Close the Dataset element 01115 out << ">\n"; 01116 } 01117 else { 01118 out << "xmlns=\"" << c_dap20_namespace << "\"\n" ; 01119 out << "xsi:schemaLocation=\"" << c_dap20_namespace 01120 << " " << c_default_dap20_schema_location << "\">\n\n" ; 01121 } 01122 01123 d_attr.print_xml(out, " ", constrained); 01124 01125 out << "\n" ; 01126 01127 for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained)); 01128 01129 out << "\n" ; 01130 01131 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 01132 // the same. 01133 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is 01134 // actually the CID of the MIME part that holds the data. 01135 if (get_dap_major() == 2 && get_dap_minor() == 0) { 01136 out << " <dataBLOB href=\"\"/>\n" ; 01137 } 01138 else if (!blob.empty() 01139 && (get_dap_major() == 3 && get_dap_minor() >= 2) 01140 || get_dap_major() >= 4) { 01141 out << " <blob href=\"cid:" << blob << "\"/>\n"; 01142 } 01143 01144 out << "</Dataset>\n" ; 01145 #endif 01146 } 01147 01148 class VariablePrintXMLWriter : public unary_function<BaseType *, void> 01149 { 01150 XMLWriter &d_xml; 01151 bool d_constrained; 01152 public: 01153 VariablePrintXMLWriter(XMLWriter &xml, bool constrained) 01154 : d_xml(xml), d_constrained(constrained) 01155 {} 01156 void operator()(BaseType *bt) 01157 { 01158 bt->print_xml_writer(d_xml, d_constrained); 01159 } 01160 }; 01161 01162 01163 void 01164 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob) 01165 { 01166 XMLWriter xml(" "); 01167 01168 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0) 01169 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element"); 01170 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name.c_str()) < 0) 01171 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01172 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0) 01173 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi"); 01174 01175 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 01176 // this at some point... jhrg 01177 if (get_dap_major() == 3 && get_dap_minor() == 2) { 01178 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0) 01179 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation"); 01180 01181 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0) 01182 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl"); 01183 01184 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0) 01185 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation"); 01186 01187 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0) 01188 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns"); 01189 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0) 01190 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap"); 01191 01192 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0) 01193 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion"); 01194 01195 if (!get_request_xml_base().empty()) { 01196 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0) 01197 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml"); 01198 01199 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0) 01200 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base"); 01201 } 01202 } 01203 else { 01204 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0) 01205 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns"); 01206 01207 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0) 01208 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation"); 01209 } 01210 01211 // Print the global attributes 01212 d_attr.print_xml_writer(xml); 01213 01214 // Print each variable 01215 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained)); 01216 01217 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 01218 // the same. 01219 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is 01220 // actually the CID of the MIME part that holds the data. 01221 if (get_dap_major() == 2 && get_dap_minor() == 0) { 01222 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0) 01223 throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element"); 01224 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)"") < 0) 01225 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01226 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01227 throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element"); 01228 } 01229 else if (!blob.empty() && (get_dap_major() == 3 && get_dap_minor() >= 2) || get_dap_major() >= 4) { 01230 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0) 01231 throw InternalErr(__FILE__, __LINE__, "Could not write blob element"); 01232 string cid="cid:" + blob; 01233 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)cid.c_str()) < 0) 01234 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01235 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01236 throw InternalErr(__FILE__, __LINE__, "Could not end blob element"); 01237 } 01238 01239 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01240 throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element"); 01241 01242 out << xml.get_doc();// << ends;// << endl; 01243 } 01244 01245 // Used by DDS::send() when returning data from a function call. 01260 bool 01261 DDS::check_semantics(bool all) 01262 { 01263 // The dataset must have a name 01264 if (name == "") { 01265 cerr << "A dataset must have a name" << endl; 01266 return false; 01267 } 01268 01269 string msg; 01270 if (!unique_names(vars, name, "Dataset", msg)) 01271 return false; 01272 01273 if (all) 01274 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01275 if (!(*i)->check_semantics(msg, true)) 01276 return false; 01277 01278 return true; 01279 } 01280 01306 bool 01307 DDS::mark(const string &n, bool state) 01308 { 01309 BaseType::btp_stack *s = new BaseType::btp_stack; 01310 01311 DBG2(cerr << "DDS::mark: Looking for " << n << endl); 01312 01313 BaseType *variable = var(n, s); 01314 if (!variable) { 01315 DBG2(cerr << "Could not find variable " << n << endl); 01316 delete s; s = 0; 01317 return false; 01318 } 01319 variable->set_send_p(state); 01320 01321 DBG2(cerr << "DDS::mark: Set variable " << variable->name() 01322 << " (a " << variable->type_name() << ")" << endl); 01323 01324 // Now check the btp_stack and run BaseType::set_send_p for every 01325 // BaseType pointer on the stack. Using BaseType::set_send_p() will 01326 // set the property for a Constructor but not its contained variables 01327 // which preserves the semantics of projecting just one field. 01328 while (!s->empty()) { 01329 s->top()->BaseType::set_send_p(state); 01330 01331 DBG2(cerr << "DDS::mark: Set variable " << s->top()->name() 01332 << " (a " << s->top()->type_name() << ")" << endl); 01333 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none"; 01334 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none"; 01335 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl); 01336 01337 s->pop(); 01338 } 01339 01340 delete s ; s = 0; 01341 01342 return true; 01343 } 01344 01350 void 01351 DDS::mark_all(bool state) 01352 { 01353 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01354 (*i)->set_send_p(state); 01355 } 01356 01364 void 01365 DDS::dump(ostream &strm) const 01366 { 01367 strm << DapIndent::LMarg << "DDS::dump - (" 01368 << (void *)this << ")" << endl ; 01369 DapIndent::Indent() ; 01370 strm << DapIndent::LMarg << "name: " << name << endl ; 01371 strm << DapIndent::LMarg << "filename: " << d_filename << endl ; 01372 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl; 01373 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl; 01374 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ; 01375 01376 strm << DapIndent::LMarg << "global attributes:" << endl ; 01377 DapIndent::Indent() ; 01378 d_attr.dump(strm) ; 01379 DapIndent::UnIndent() ; 01380 01381 if (vars.size()) { 01382 strm << DapIndent::LMarg << "vars:" << endl ; 01383 DapIndent::Indent() ; 01384 Vars_citer i = vars.begin() ; 01385 Vars_citer ie = vars.end() ; 01386 for (; i != ie; i++) { 01387 (*i)->dump(strm) ; 01388 } 01389 DapIndent::UnIndent() ; 01390 } 01391 else { 01392 strm << DapIndent::LMarg << "vars: none" << endl ; 01393 } 01394 01395 DapIndent::UnIndent() ; 01396 } 01397 01398 } // namespace libdap