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 24370 2011-03-28 16:21:32Z 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 grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl"; 00095 00096 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace"; 00097 00098 using namespace std; 00099 00100 void ddsrestart(FILE *yyin); // Defined in dds.tab.c 00101 int ddsparse(void *arg); 00102 00103 // Glue for the DDS parser defined in dds.lex 00104 void dds_switch_to_buffer(void *new_buffer); 00105 void dds_delete_buffer(void * buffer); 00106 void *dds_buffer(FILE *fp); 00107 00108 namespace libdap { 00109 00110 void 00111 DDS::duplicate(const DDS &dds) 00112 { 00113 DBG(cerr << "Entering DDS::duplicate... " <<endl); 00114 name = dds.name; 00115 d_filename = dds.d_filename; 00116 d_container_name = dds.d_container_name; 00117 d_timeout = dds.d_timeout; 00118 d_attr = dds.d_attr; 00119 00120 d_factory = dds.d_factory; 00121 d_container = dds.d_container; 00122 d_dap_major = dds.d_dap_major; 00123 d_dap_minor = dds.d_dap_minor; 00124 00125 d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers 00126 00127 DDS &dds_tmp = const_cast<DDS &>(dds); 00128 00129 // copy the things pointed to by the list, not just the pointers 00130 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) { 00131 add_var(*i); // add_var() dups the BaseType. 00132 } 00133 } 00134 00145 DDS::DDS(BaseTypeFactory *factory, const string &n) 00146 00147 : d_factory(factory), name(n), d_container(0), 00148 d_dap_major(2), d_dap_minor(0), 00149 d_request_xml_base(""), d_timeout(0), d_keywords() 00150 { 00151 DBG(cerr << "Building a DDS with client major/minor: " 00152 << d_dap_major << "." << d_dap_minor << endl); 00153 } 00154 00156 DDS::DDS(const DDS &rhs) : DapObj() 00157 { 00158 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl); 00159 duplicate(rhs); 00160 DBG(cerr << " bye." << endl); 00161 } 00162 00163 DDS::~DDS() 00164 { 00165 // delete all the variables in this DDS 00166 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00167 BaseType *btp = *i ; 00168 delete btp ; btp = 0; 00169 } 00170 } 00171 00172 DDS & 00173 DDS::operator=(const DDS &rhs) 00174 { 00175 DBG(cerr << "Entering DDS::operator= ..." << endl); 00176 if (this == &rhs) 00177 return *this; 00178 00179 duplicate(rhs); 00180 00181 DBG(cerr << " bye." << endl); 00182 return *this; 00183 } 00184 00198 void 00199 DDS::transfer_attributes(DAS *das) 00200 { 00201 // If there is a container set in the DDS then get the container from 00202 // the DAS. If they are not the same container, then throw an exception 00203 // (should be working on the same container). If the container does not 00204 // exist in the DAS, then throw an exception 00205 if( d_container ) { 00206 if( das->container_name() != d_container_name ) 00207 throw InternalErr(__FILE__, __LINE__, "Error transferring attributes: working on a container in dds, but not das" ) ; 00208 } 00209 00210 // Give each variable a chance to claim its attributes. 00211 AttrTable *top_level = das->get_top_level_attributes() ; 00212 00213 Vars_iter var = var_begin(); 00214 while (var != var_end()) { 00215 (*var)->transfer_attributes(top_level); 00216 var++; 00217 } 00218 00219 // Now we transfer all of the attributes still marked as global to the 00220 // global container in the DDS. 00221 00222 AttrTable::Attr_iter at_cont_p = top_level->attr_begin(); 00223 while (at_cont_p != top_level->attr_end()) { 00224 // In truth, all of the top level attributes should be containers, but 00225 // this test handles the abnormal case where somehow someone makes a 00226 // top level attribute that is not a container by silently dropping it. 00227 if ((*at_cont_p)->type == Attr_container 00228 && (*at_cont_p)->attributes->is_global_attribute()) { 00229 DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl); 00230 // copy the source container so that the DAS passed in can be 00231 // deleted after calling htis method. 00232 AttrTable *at = new AttrTable(*(*at_cont_p)->attributes); 00233 d_attr.append_container(at, at->get_name()); 00234 } 00235 00236 at_cont_p++; 00237 } 00238 } 00239 00247 00249 string 00250 DDS::get_dataset_name() const 00251 { 00252 return name; 00253 } 00254 00256 void 00257 DDS::set_dataset_name(const string &n) 00258 { 00259 name = n; 00260 } 00261 00263 00265 AttrTable & 00266 DDS::get_attr_table() 00267 { 00268 return d_attr; 00269 } 00270 00280 string 00281 DDS::filename() 00282 { 00283 return d_filename; 00284 } 00285 00287 void 00288 DDS::filename(const string &fn) 00289 { 00290 d_filename = fn; 00291 } 00293 00294 void 00295 DDS::set_dap_major(int p) 00296 { 00297 d_dap_major = p; 00298 00299 // This works because regardless of the order set_dap_major and set_dap_minor 00300 // are called, once they both are called, the value in the string is 00301 // correct. I protect against negative numbers because that would be 00302 // nonsensical. 00303 if (d_dap_minor >= 0) { 00304 ostringstream oss; 00305 oss << d_dap_major << "." << d_dap_minor; 00306 d_dap_version = oss.str(); 00307 } 00308 } 00309 00310 void 00311 DDS::set_dap_minor(int p) 00312 { 00313 d_dap_minor = p; 00314 00315 if (d_dap_major >= 0) { 00316 ostringstream oss; 00317 oss << d_dap_major << "." << d_dap_minor; 00318 d_dap_version = oss.str(); 00319 } 00320 } 00321 00328 void 00329 DDS::set_dap_version(const string &version_string) 00330 { 00331 istringstream iss(version_string); 00332 00333 int major = -1, minor = -1; 00334 char dot; 00335 if (!iss.eof() && !iss.fail()) 00336 iss >> major; 00337 if (!iss.eof() && !iss.fail()) 00338 iss >> dot; 00339 if (!iss.eof() && !iss.fail()) 00340 iss >> minor; 00341 00342 DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl); 00343 #if 0 00344 if (major == -1 || minor == -1) 00345 throw Error("Could not parse the client dap (XDAP-Accept header) value"); 00346 #endif 00347 00348 d_dap_version = version_string; 00349 00350 set_dap_major(major == -1 ? 2 : major); 00351 set_dap_minor(minor == -1 ? 0 : minor); 00352 } 00353 00361 void 00362 DDS::set_dap_version(double d) 00363 { 00364 int major = d; 00365 int minor = (d-major)*10; 00366 00367 DBG(cerr << "Major: " << major << ", Minor: " << minor << endl); 00368 00369 ostringstream oss; 00370 oss << major << "." << minor; 00371 d_dap_version = oss.str(); 00372 00373 set_dap_major(major); 00374 set_dap_minor(minor); 00375 } 00376 00386 string 00387 DDS::container_name() 00388 { 00389 return d_container_name; 00390 } 00391 00394 void 00395 DDS::container_name(const string &cn) 00396 { 00397 // we want to search the DDS for the top level structure with the given 00398 // name. Set the container to null so that we don't search some previous 00399 // container. 00400 d_container = 0 ; 00401 if( !cn.empty() ) 00402 { 00403 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00404 if( !d_container ) 00405 { 00406 // create a structure for this container. Calling add_var 00407 // while_container is null will add the new structure to DDS and 00408 // not some sub structure. Adding the new structure makes a copy 00409 // of it. So after adding it, go get it and set d_container. 00410 Structure *s = new Structure( cn ) ; 00411 add_var( s ) ; 00412 delete s ; 00413 s = 0 ; 00414 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00415 } 00416 } 00417 d_container_name = cn; 00418 00419 } 00420 00422 Structure * 00423 DDS::container() 00424 { 00425 return d_container ; 00426 } 00427 00429 00435 void 00436 DDS::add_var(BaseType *bt) 00437 { 00438 if (!bt) 00439 throw InternalErr(__FILE__, __LINE__, 00440 "Trying to add a BaseType object with a NULL pointer."); 00441 00442 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl); 00443 00444 BaseType *btp = bt->ptr_duplicate(); 00445 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl); 00446 if( d_container ) 00447 { 00448 // Mem leak fix [mjohnson nov 2009] 00449 // Structure::add_var() creates ANOTHER copy. 00450 d_container->add_var( bt ) ; 00451 // So we need to delete btp or else it leaks 00452 delete btp; btp = 0; 00453 } 00454 else 00455 { 00456 vars.push_back(btp); 00457 } 00458 } 00459 00466 void 00467 DDS::del_var(const string &n) 00468 { 00469 if( d_container ) 00470 { 00471 d_container->del_var( n ) ; 00472 return ; 00473 } 00474 00475 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00476 if ((*i)->name() == n) { 00477 BaseType *bt = *i ; 00478 vars.erase(i) ; 00479 delete bt ; bt = 0; 00480 return; 00481 } 00482 } 00483 } 00484 00489 void 00490 DDS::del_var(Vars_iter i) 00491 { 00492 if (i != vars.end()) { 00493 BaseType *bt = *i ; 00494 vars.erase(i) ; 00495 delete bt ; bt = 0; 00496 } 00497 } 00498 00505 void 00506 DDS::del_var(Vars_iter i1, Vars_iter i2) 00507 { 00508 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) { 00509 BaseType *bt = *i_tmp ; 00510 delete bt ; bt = 0; 00511 } 00512 vars.erase(i1, i2) ; 00513 } 00514 00522 BaseType * 00523 DDS::var(const string &n, BaseType::btp_stack &s) 00524 { 00525 return var(n, &s); 00526 } 00546 BaseType * 00547 DDS::var(const string &n, BaseType::btp_stack *s) 00548 { 00549 string name = www2id(n); 00550 if( d_container ) 00551 return d_container->var( name, false, s ) ; 00552 00553 BaseType *v = exact_match(name, s); 00554 if (v) 00555 return v; 00556 00557 return leaf_match(name, s); 00558 } 00559 00560 BaseType * 00561 DDS::leaf_match(const string &n, BaseType::btp_stack *s) 00562 { 00563 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl); 00564 00565 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00566 BaseType *btp = *i; 00567 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl); 00568 // Look for the name in the dataset's top-level 00569 if (btp->name() == n) { 00570 DBG(cerr << "Found " << n << " in: " << btp->name() << endl); 00571 return btp; 00572 } 00573 00574 if (btp->is_constructor_type()) { 00575 BaseType *found = btp->var(n, false, s); 00576 if (found) { 00577 DBG(cerr << "Found " << n << " in: " << btp->name() << endl); 00578 return found; 00579 } 00580 } 00581 #if STRUCTURE_ARRAY_SYNTAX_OLD 00582 if (btp->is_vector_type() && btp->var()->is_constructor_type()) { 00583 s->push(btp); 00584 BaseType *found = btp->var()->var(n, false, s); 00585 if (found) { 00586 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl); 00587 return found; 00588 } 00589 } 00590 #endif 00591 } 00592 00593 return 0; // It is not here. 00594 } 00595 00596 BaseType * 00597 DDS::exact_match(const string &name, BaseType::btp_stack *s) 00598 { 00599 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00600 BaseType *btp = *i; 00601 DBG2(cerr << "Looking for " << name << " in: " << btp << endl); 00602 // Look for the name in the current ctor type or the top level 00603 if (btp->name() == name) { 00604 DBG2(cerr << "Found " << name << " in: " << btp << endl); 00605 return btp; 00606 } 00607 } 00608 00609 string::size_type dot_pos = name.find("."); 00610 if (dot_pos != string::npos) { 00611 string aggregate = name.substr(0, dot_pos); 00612 string field = name.substr(dot_pos + 1); 00613 00614 BaseType *agg_ptr = var(aggregate, s); 00615 if (agg_ptr) { 00616 DBG2(cerr << "Descending into " << agg_ptr->name() << endl); 00617 return agg_ptr->var(field, true, s); 00618 } 00619 else 00620 return 0; // qualified names must be *fully* qualified 00621 } 00622 00623 return 0; // It is not here. 00624 } 00625 00626 00629 DDS::Vars_iter 00630 DDS::var_begin() 00631 { 00632 return vars.begin(); 00633 } 00634 00635 DDS::Vars_riter 00636 DDS::var_rbegin() 00637 { 00638 return vars.rbegin(); 00639 } 00640 00641 DDS::Vars_iter 00642 DDS::var_end() 00643 { 00644 return vars.end() ; 00645 } 00646 00647 DDS::Vars_riter 00648 DDS::var_rend() 00649 { 00650 return vars.rend() ; 00651 } 00652 00656 DDS::Vars_iter 00657 DDS::get_vars_iter(int i) 00658 { 00659 return vars.begin() + i; 00660 } 00661 00665 BaseType * 00666 DDS::get_var_index(int i) 00667 { 00668 return *(vars.begin() + i); 00669 } 00670 00672 int 00673 DDS::num_var() 00674 { 00675 return vars.size(); 00676 } 00677 00678 void 00679 DDS::timeout_on() 00680 { 00681 #ifndef WIN32 00682 alarm(d_timeout); 00683 #endif 00684 } 00685 00686 void 00687 DDS::timeout_off() 00688 { 00689 #ifndef WIN32 00690 d_timeout = alarm(0); 00691 #endif 00692 } 00693 00694 void 00695 DDS::set_timeout(int t) 00696 { 00697 // Has no effect under win32 00698 d_timeout = t; 00699 } 00700 00701 int 00702 DDS::get_timeout() 00703 { 00704 // Has to effect under win32 00705 return d_timeout; 00706 } 00707 00709 void 00710 DDS::tag_nested_sequences() 00711 { 00712 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00713 if ((*i)->type() == dods_sequence_c) 00714 dynamic_cast<Sequence&>(**i).set_leaf_sequence(); 00715 else if ((*i)->type() == dods_structure_c) 00716 dynamic_cast<Structure&>(**i).set_leaf_sequence(); 00717 } 00718 } 00719 00721 void 00722 DDS::parse(string fname) 00723 { 00724 FILE *in = fopen(fname.c_str(), "r"); 00725 00726 if (!in) { 00727 throw Error(cannot_read_file, "Could not open: " + fname); 00728 } 00729 00730 try { 00731 parse(in); 00732 fclose(in); 00733 } 00734 catch (Error &e) { 00735 fclose(in); 00736 throw ; 00737 } 00738 } 00739 00740 00742 void 00743 DDS::parse(int fd) 00744 { 00745 #ifdef WIN32 00746 FILE *in = fdopen(_dup(fd), "r"); 00747 #else 00748 FILE *in = fdopen(dup(fd), "r"); 00749 #endif 00750 00751 if (!in) { 00752 throw InternalErr(__FILE__, __LINE__, "Could not access file."); 00753 } 00754 00755 try { 00756 parse(in); 00757 fclose(in); 00758 } 00759 catch (Error &e) { 00760 fclose(in); 00761 throw ; 00762 } 00763 } 00764 00771 void 00772 DDS::parse(FILE *in) 00773 { 00774 if (!in) { 00775 throw InternalErr(__FILE__, __LINE__, "Null input stream."); 00776 } 00777 00778 void *buffer = dds_buffer(in); 00779 dds_switch_to_buffer(buffer); 00780 00781 parser_arg arg(this); 00782 00783 bool status = ddsparse((void *) & arg) == 0; 00784 00785 dds_delete_buffer(buffer); 00786 00787 DBG2(cout << "Status from parser: " << status << endl); 00788 00789 // STATUS is the result of the parser function; if a recoverable error 00790 // was found it will be true but arg.status() will be false. 00791 if (!status || !arg.status()) {// Check parse result 00792 if (arg.error()) 00793 throw *arg.error(); 00794 } 00795 } 00796 00797 #if FILE_METHODS 00798 00799 void 00800 DDS::print(FILE *out) 00801 { 00802 #if 0 00803 ostringstream oss; 00804 print(oss); 00805 00806 fwrite(oss.str().c_str(), oss.str().length(), 1, out); 00807 #else 00808 fprintf(out, "Dataset {\n") ; 00809 00810 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00811 (*i)->print_decl(out) ; 00812 } 00813 00814 fprintf(out, "} %s;\n", id2www(name).c_str()) ; 00815 00816 return ; 00817 #endif 00818 } 00819 #endif 00820 00822 void 00823 DDS::print(ostream &out) 00824 { 00825 out << "Dataset {\n" ; 00826 00827 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00828 (*i)->print_decl(out) ; 00829 } 00830 00831 out << "} " << id2www(name) << ";\n" ; 00832 00833 return ; 00834 } 00835 00836 #if FILE_METHODS 00837 00847 void 00848 DDS::print_constrained(FILE *out) 00849 { 00850 fprintf(out, "Dataset {\n") ; 00851 00852 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00853 // for each variable, indent with four spaces, print a trailing 00854 // semicolon, do not print debugging information, print only 00855 // variables in the current projection. 00856 (*i)->print_decl(out, " ", true, false, true) ; 00857 } 00858 00859 fprintf(out, "} %s;\n", id2www(name).c_str()) ; 00860 00861 return; 00862 } 00863 #endif 00864 00875 void 00876 DDS::print_constrained(ostream &out) 00877 { 00878 out << "Dataset {\n" ; 00879 00880 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00881 // for each variable, indent with four spaces, print a trailing 00882 // semicolon, do not print debugging information, print only 00883 // variables in the current projection. 00884 (*i)->print_decl(out, " ", true, false, true) ; 00885 } 00886 00887 out << "} " << id2www(name) << ";\n" ; 00888 00889 return; 00890 } 00891 00892 #if FILE_METHODS 00893 class VariablePrintXML : public unary_function<BaseType *, void> 00894 { 00895 FILE *d_out; 00896 bool d_constrained; 00897 public: 00898 VariablePrintXML(FILE *out, bool constrained) 00899 : d_out(out), d_constrained(constrained) 00900 {} 00901 void operator()(BaseType *bt) 00902 { 00903 bt->print_xml(d_out, " ", d_constrained); 00904 } 00905 }; 00906 00917 void 00918 DDS::print_xml(FILE *out, bool constrained, const string &blob) 00919 { 00920 fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 00921 00922 fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str()); 00923 00924 fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); 00925 00926 fprintf(out,"method=\"FILE*\"\n"); 00927 fprintf(out, "dap_major=\"%d\"\n", get_dap_major()); 00928 fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor()); 00929 00930 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 00931 // this at some point... jhrg 00932 if (get_dap_major() == 3 && get_dap_minor() == 2) { 00933 fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str()); 00934 00935 fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n", 00936 c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str()); 00937 } 00938 else { 00939 fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str()); 00940 fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n", 00941 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str()); 00942 } 00943 00944 00945 d_attr.print_xml(out, " ", constrained); 00946 00947 fprintf(out, "\n"); 00948 00949 for_each(var_begin(), var_end(), VariablePrintXML(out, constrained)); 00950 00951 fprintf(out, "\n"); 00952 00953 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 00954 // the same. jhrg 00955 if (get_dap_major() == 2 && get_dap_minor() == 0) { 00956 fprintf(out, " <dataBLOB href=\"\"/>\n"); 00957 } 00958 else if (!blob.empty() 00959 && (get_dap_major() == 3 && get_dap_minor() >= 2) 00960 || get_dap_major() >= 4) { 00961 fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str()); 00962 } 00963 00964 00965 fprintf(out, "</Dataset>\n"); 00966 } 00967 #endif 00968 00969 class VariablePrintXMLStrm : public unary_function<BaseType *, void> 00970 { 00971 ostream &d_out; 00972 bool d_constrained; 00973 public: 00974 VariablePrintXMLStrm(ostream &out, bool constrained) 00975 : d_out(out), d_constrained(constrained) 00976 {} 00977 void operator()(BaseType *bt) 00978 { 00979 bt->print_xml(d_out, " ", d_constrained); 00980 } 00981 }; 00982 00993 void 00994 DDS::print_xml(ostream &out, bool constrained, const string &blob) 00995 { 00996 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ; 00997 00998 out << "<Dataset name=\"" << id2xml(name) << "\"\n" ; 00999 01000 out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ; 01001 01002 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 01003 // this at some point... jhrg 01004 if (get_dap_major() == 3 && get_dap_minor() == 2) { 01005 out << "xsi:schemaLocation=\"" << c_dap32_namespace 01006 << " " << c_default_dap32_schema_location << "\"\n" ; 01007 01008 out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n"; 01009 out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n"; 01010 01011 out << "xmlns=\"" << c_dap32_namespace << "\"\n" ; 01012 out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ; 01013 01014 out << "dapVersion=\"" << get_dap_major() << "." 01015 << get_dap_minor() << "\""; 01016 01017 if (!get_request_xml_base().empty()) { 01018 out << "\n"; 01019 out << "xmlns:xml=\"" << c_xml_namespace << "\"\n"; 01020 out << "xml:base=\"" << get_request_xml_base() << "\""; 01021 } 01022 01023 // Close the Dataset element 01024 out << ">\n"; 01025 } 01026 else { 01027 out << "xmlns=\"" << c_dap20_namespace << "\"\n" ; 01028 out << "xsi:schemaLocation=\"" << c_dap20_namespace 01029 << " " << c_default_dap20_schema_location << "\">\n\n" ; 01030 } 01031 01032 d_attr.print_xml(out, " ", constrained); 01033 01034 out << "\n" ; 01035 01036 for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained)); 01037 01038 out << "\n" ; 01039 01040 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 01041 // the same. 01042 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is 01043 // actually the CID of the MIME part that holds the data. 01044 if (get_dap_major() == 2 && get_dap_minor() == 0) { 01045 out << " <dataBLOB href=\"\"/>\n" ; 01046 } 01047 else if (!blob.empty() 01048 && (get_dap_major() == 3 && get_dap_minor() >= 2) 01049 || get_dap_major() >= 4) { 01050 out << " <blob href=\"cid:" << blob << "\"/>\n"; 01051 } 01052 01053 out << "</Dataset>\n" ; 01054 } 01055 01056 // Used by DDS::send() when returning data from a function call. 01071 bool 01072 DDS::check_semantics(bool all) 01073 { 01074 // The dataset must have a name 01075 if (name == "") { 01076 cerr << "A dataset must have a name" << endl; 01077 return false; 01078 } 01079 01080 string msg; 01081 if (!unique_names(vars, name, "Dataset", msg)) 01082 return false; 01083 01084 if (all) 01085 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01086 if (!(*i)->check_semantics(msg, true)) 01087 return false; 01088 01089 return true; 01090 } 01091 01117 bool 01118 DDS::mark(const string &n, bool state) 01119 { 01120 BaseType::btp_stack *s = new BaseType::btp_stack; 01121 01122 DBG2(cerr << "DDS::mark: Looking for " << n << endl); 01123 01124 BaseType *variable = var(n, s); 01125 if (!variable) { 01126 DBG2(cerr << "Could not find variable " << n << endl); 01127 delete s; s = 0; 01128 return false; 01129 } 01130 variable->set_send_p(state); 01131 01132 DBG2(cerr << "DDS::mark: Set variable " << variable->name() 01133 << " (a " << variable->type_name() << ")" << endl); 01134 01135 // Now check the btp_stack and run BaseType::set_send_p for every 01136 // BaseType pointer on the stack. Using BaseType::set_send_p() will 01137 // set the property for a Constructor but not its contained variables 01138 // which preserves the semantics of projecting just one field. 01139 while (!s->empty()) { 01140 s->top()->BaseType::set_send_p(state); 01141 01142 DBG2(cerr << "DDS::mark: Set variable " << s->top()->name() 01143 << " (a " << s->top()->type_name() << ")" << endl); 01144 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none"; 01145 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none"; 01146 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl); 01147 01148 s->pop(); 01149 } 01150 01151 delete s ; s = 0; 01152 01153 return true; 01154 } 01155 01161 void 01162 DDS::mark_all(bool state) 01163 { 01164 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01165 (*i)->set_send_p(state); 01166 } 01167 01175 void 01176 DDS::dump(ostream &strm) const 01177 { 01178 strm << DapIndent::LMarg << "DDS::dump - (" 01179 << (void *)this << ")" << endl ; 01180 DapIndent::Indent() ; 01181 strm << DapIndent::LMarg << "name: " << name << endl ; 01182 strm << DapIndent::LMarg << "filename: " << d_filename << endl ; 01183 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl; 01184 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl; 01185 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ; 01186 01187 strm << DapIndent::LMarg << "global attributes:" << endl ; 01188 DapIndent::Indent() ; 01189 d_attr.dump(strm) ; 01190 DapIndent::UnIndent() ; 01191 01192 if (vars.size()) { 01193 strm << DapIndent::LMarg << "vars:" << endl ; 01194 DapIndent::Indent() ; 01195 Vars_citer i = vars.begin() ; 01196 Vars_citer ie = vars.end() ; 01197 for (; i != ie; i++) { 01198 (*i)->dump(strm) ; 01199 } 01200 DapIndent::UnIndent() ; 01201 } 01202 else { 01203 strm << DapIndent::LMarg << "vars: none" << endl ; 01204 } 01205 01206 DapIndent::UnIndent() ; 01207 } 01208 01209 } // namespace libdap