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 23577 2010-09-14 22:20:18Z 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 00067 #include "parser.h" 00068 #include "debug.h" 00069 #include "util.h" 00070 00071 #include "Byte.h" 00072 #include "Int16.h" 00073 #include "UInt16.h" 00074 #include "Int32.h" 00075 #include "UInt32.h" 00076 #include "Float32.h" 00077 #include "Float64.h" 00078 #include "Str.h" 00079 #include "Url.h" 00080 #include "Array.h" 00081 #include "Structure.h" 00082 #include "Sequence.h" 00083 #include "Grid.h" 00084 00085 #include "escaping.h" 00086 00087 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd"; 00088 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd"; 00089 00090 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2"; 00091 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#"; 00092 00093 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl"; 00094 00095 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace"; 00096 00097 using namespace std; 00098 00099 void ddsrestart(FILE *yyin); // Defined in dds.tab.c 00100 int ddsparse(void *arg); 00101 00102 // Glue for the DDS parser defined in dds.lex 00103 void dds_switch_to_buffer(void *new_buffer); 00104 void dds_delete_buffer(void * buffer); 00105 void *dds_buffer(FILE *fp); 00106 00107 namespace libdap { 00108 00109 void 00110 DDS::duplicate(const DDS &dds) 00111 { 00112 DBG(cerr << "Entering DDS::duplicate... " <<endl); 00113 name = dds.name; 00114 d_filename = dds.d_filename; 00115 d_container_name = dds.d_container_name; 00116 d_timeout = dds.d_timeout; 00117 d_attr = dds.d_attr; 00118 00119 d_factory = dds.d_factory; 00120 d_container = dds.d_container; 00121 d_dap_major = dds.d_dap_major; 00122 d_dap_minor = dds.d_dap_minor; 00123 00124 DDS &dds_tmp = const_cast<DDS &>(dds); 00125 00126 // copy the things pointed to by the list, not just the pointers 00127 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) { 00128 add_var(*i); // add_var() dups the BaseType. 00129 } 00130 } 00131 00142 DDS::DDS(BaseTypeFactory *factory, const string &n) 00143 00144 : d_factory(factory), name(n), d_container(0), d_dap_major(2), 00145 d_dap_minor(0), 00146 d_request_xml_base(""), d_timeout(0) 00147 { 00148 DBG(cerr << "Building a DDS with client major/minor: " 00149 << d_dap_major << "." << d_dap_minor << endl); 00150 } 00151 00153 DDS::DDS(const DDS &rhs) : DapObj() 00154 { 00155 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl); 00156 duplicate(rhs); 00157 DBG(cerr << " bye." << endl); 00158 } 00159 00160 DDS::~DDS() 00161 { 00162 // delete all the variables in this DDS 00163 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00164 BaseType *btp = *i ; 00165 delete btp ; btp = 0; 00166 } 00167 } 00168 00169 DDS & 00170 DDS::operator=(const DDS &rhs) 00171 { 00172 DBG(cerr << "Entering DDS::operator= ..." << endl); 00173 if (this == &rhs) 00174 return *this; 00175 00176 duplicate(rhs); 00177 00178 DBG(cerr << " bye." << endl); 00179 return *this; 00180 } 00181 00182 #if 0 00183 00198 BaseType * 00199 DDS::find_hdf4_dimension_attribute_home(AttrTable::entry *source) 00200 { 00201 BaseType *btp; 00202 string::size_type i = source->name.find("_dim_"); 00203 if (i != string::npos && (btp = var(source->name.substr(0, i)))) { 00204 if (btp->is_vector_type()) { 00205 return btp; 00206 } 00207 else if (btp->type() == dods_grid_c) { 00208 // For a Grid, the hdf4 handler uses _dim_n for the n-th Map 00209 // i+5 points to the character holding 'n' 00210 int n = atoi(source->name.substr(i + 5).c_str()); 00211 DBG(cerr << "Found a Grid (" << btp->name() << ") and " 00212 << source->name.substr(i) << ", extracted n: " << n << endl); 00213 return *(dynamic_cast<Grid&>(*btp).map_begin() + n); 00214 } 00215 } 00216 00217 return 0; 00218 } 00219 00225 AttrTable * 00226 DDS::find_matching_container(AttrTable::entry *source, BaseType **dest_variable) 00227 { 00228 // The attribute entry 'source' must be a container 00229 if (source->type != Attr_container) 00230 throw InternalErr(__FILE__, __LINE__, "DDS::find_matching_container; expected 'source' to be a container."); 00231 00232 // Use the name of the attribute container 'source' to figure out where 00233 // to put its contents. 00234 BaseType *btp; 00235 if ((btp = var(source->name))) { 00236 // ... matches a variable name? Use var's table 00237 *dest_variable = btp; 00238 return &btp->get_attr_table(); 00239 } 00240 else if ((btp = find_hdf4_dimension_attribute_home(source))) { 00241 // ... hdf4 dimension attribute? Make a sub table and use that. 00242 // btp can only be an Array or a Grid Map (which is an array) 00243 if (btp->get_parent() && btp->get_parent()->type() == dods_grid_c) { 00244 DBG(cerr << "Found a Grid, assigning to the map" << endl); 00245 *dest_variable = btp; 00246 return &btp->get_attr_table(); 00247 } 00248 else { // must be a plain Array 00249 string::size_type i = source->name.find("_dim_"); 00250 string ext = source->name.substr(i + 1); 00251 *dest_variable = btp; 00252 return btp->get_attr_table().append_container(ext); 00253 } 00254 } 00255 else { 00256 // ... otherwise assume it's a global attribute. 00257 AttrTable *at = d_attr.find_container(source->name); 00258 if (!at) { 00259 at = new AttrTable(); // Make a new global table if needed 00260 d_attr.append_container(at, source->name); 00261 } 00262 00263 *dest_variable = 0; 00264 return at; 00265 } 00266 } 00267 00289 void 00290 DDS::transfer_attributes(DAS *das) 00291 { 00292 // If there is a container set in the DDS then get the container from 00293 // the DAS. If they are not the same container, then throw an exception 00294 // (should be working on the same container). If the container does not 00295 // exist in the DAS, then throw an exception 00296 if( d_container ) 00297 { 00298 if( das->container_name() != d_container_name ) 00299 { 00300 string err = (string)"Error transferring attributes: " 00301 + "working on container in dds, but not das" ; 00302 throw InternalErr(__FILE__, __LINE__, err ) ; 00303 } 00304 } 00305 00306 AttrTable *top_level = das->get_top_level_attributes() ; 00307 00308 // foreach container at the outer level 00309 AttrTable::Attr_iter das_i = top_level->attr_begin(); 00310 AttrTable::Attr_iter das_e = top_level->attr_end(); 00311 while (das_i != das_e) { 00312 DBG(cerr << "Working on the '" << (*das_i)->name << "' container." 00313 << endl); 00314 00315 AttrTable *source = (*das_i)->attributes; 00316 // Variable that holds 'dest'; null for a global attribute. 00317 BaseType *dest_variable = 0; 00318 AttrTable *dest = find_matching_container(*das_i, &dest_variable); 00319 00320 // foreach source attribute in the das_i container 00321 AttrTable::Attr_iter source_p = source->attr_begin(); 00322 while (source_p != source->attr_end()) { 00323 DBG(cerr << "Working on the '" << (*source_p)->name << "' attribute" 00324 << endl); 00325 00326 // If this is an attribute container, we must have a container 00327 // (this one) within a container (the 'source'). Look and see if 00328 // the variable is a Constructor. If so, pass that container into 00329 // Constructor::transfer_attributes() 00330 if ((*source_p)->type == Attr_container) { 00331 if (dest_variable && dest_variable->is_constructor_type()) { 00332 dynamic_cast<Constructor&>(*dest_variable).transfer_attributes(*source_p); 00333 } 00334 else { 00335 dest->append_container(new AttrTable(*(*source_p)->attributes), 00336 (*source_p)->name); 00337 } 00338 } 00339 else { 00340 dest->append_attr(source->get_name(source_p), 00341 source->get_type(source_p), 00342 source->get_attr_vector(source_p)); 00343 } 00344 00345 ++source_p; 00346 } 00347 00348 ++das_i; 00349 } 00350 } 00351 #endif 00352 00366 void 00367 DDS::transfer_attributes(DAS *das) 00368 { 00369 // If there is a container set in the DDS then get the container from 00370 // the DAS. If they are not the same container, then throw an exception 00371 // (should be working on the same container). If the container does not 00372 // exist in the DAS, then throw an exception 00373 if( d_container ) 00374 { 00375 if( das->container_name() != d_container_name ) 00376 throw InternalErr(__FILE__, __LINE__, "Error transferring attributes: working on a container in dds, but not das" ) ; 00377 } 00378 00379 // Give each variable a chance to claim its attributes. 00380 AttrTable *top_level = das->get_top_level_attributes() ; 00381 00382 Vars_iter var = var_begin(); 00383 while (var != var_end()) { 00384 (*var)->transfer_attributes(top_level); 00385 var++; 00386 } 00387 00388 // Now we transfer all of the attributes still marked as global to the 00389 // global container in the DDS. 00390 00391 AttrTable::Attr_iter at_cont_p = top_level->attr_begin(); 00392 while (at_cont_p != top_level->attr_end()) { 00393 // In truth, all of the top level attributes should be containers, but 00394 // this test handles the abnormal case where somehow someone makes a 00395 // top level attribute that is not a container by silently dropping it. 00396 if ((*at_cont_p)->type == Attr_container 00397 && (*at_cont_p)->attributes->is_global_attribute()) { 00398 DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl); 00399 // copy the source container so that the DAS passed in can be 00400 // deleted after calling htis method. 00401 AttrTable *at = new AttrTable(*(*at_cont_p)->attributes); 00402 d_attr.append_container(at, at->get_name()); 00403 } 00404 00405 at_cont_p++; 00406 } 00407 } 00408 00409 #if 0 00410 // cruft from the above method 00411 00412 AttrTable *dest = d_attr.find_container(at->get_name()); 00413 if (!dest) { 00414 cerr << "making a new sub containter for it" << endl; 00415 // If there's currently no top level container with this 00416 //container's name (the typical case) make one. 00417 dest = new AttrTable(); // Make a new global table if needed 00418 d_attr.append_container(dest, at->get_name()); 00419 } 00420 00421 cerr << "now copying its contents to the new container" << endl; 00422 // Now copy all of the global attribute's stuff into the matching 00423 // container in the DDS. 00424 AttrTable::Attr_iter at_p = at->attr_begin(); 00425 while (at_p != at->attr_end()) { 00426 if (at->get_attr_type(at_p) == Attr_container) 00427 dest->append_container(at->get_attr_table(at_p), at->get_name(at_p)); 00428 else 00429 dest->append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p)); 00430 at_p++; 00431 } 00432 #endif 00433 00441 00443 string 00444 DDS::get_dataset_name() const 00445 { 00446 return name; 00447 } 00448 00450 void 00451 DDS::set_dataset_name(const string &n) 00452 { 00453 name = n; 00454 } 00455 00457 00459 AttrTable & 00460 DDS::get_attr_table() 00461 { 00462 return d_attr; 00463 } 00464 00474 string 00475 DDS::filename() 00476 { 00477 return d_filename; 00478 } 00479 00481 void 00482 DDS::filename(const string &fn) 00483 { 00484 d_filename = fn; 00485 } 00487 00493 void 00494 DDS::set_dap_version(const string &version_string) 00495 { 00496 istringstream iss(version_string); 00497 00498 int major = -1, minor = -1; 00499 char dot; 00500 iss >> major; 00501 iss >> dot; 00502 iss >> minor; 00503 00504 DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl); 00505 00506 if (major == -1 || minor == -1) 00507 throw Error("Could not parse the client dap (XDAP-Accept header) value"); 00508 00509 set_dap_major(major); 00510 set_dap_minor(minor); 00511 } 00512 00522 string 00523 DDS::container_name() 00524 { 00525 return d_container_name; 00526 } 00527 00530 void 00531 DDS::container_name(const string &cn) 00532 { 00533 // we want to search the DDS for the top level structure with the given 00534 // name. Set the container to null so that we don't search some previous 00535 // container. 00536 d_container = 0 ; 00537 if( !cn.empty() ) 00538 { 00539 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00540 if( !d_container ) 00541 { 00542 // create a structure for this container. Calling add_var 00543 // while_container is null will add the new structure to DDS and 00544 // not some sub structure. Adding the new structure makes a copy 00545 // of it. So after adding it, go get it and set d_container. 00546 Structure *s = new Structure( cn ) ; 00547 add_var( s ) ; 00548 delete s ; 00549 s = 0 ; 00550 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00551 } 00552 } 00553 d_container_name = cn; 00554 00555 } 00556 00558 Structure * 00559 DDS::container() 00560 { 00561 return d_container ; 00562 } 00563 00565 00571 void 00572 DDS::add_var(BaseType *bt) 00573 { 00574 if (!bt) 00575 throw InternalErr(__FILE__, __LINE__, 00576 "Trying to add a BaseType object with a NULL pointer."); 00577 00578 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl); 00579 00580 BaseType *btp = bt->ptr_duplicate(); 00581 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl); 00582 if( d_container ) 00583 { 00584 // Mem leak fix [mjohnson nov 2009] 00585 // Structure::add_var() creates ANOTHER copy. 00586 d_container->add_var( bt ) ; 00587 // So we need to delete btp or else it leaks 00588 delete btp; btp = 0; 00589 } 00590 else 00591 { 00592 vars.push_back(btp); 00593 } 00594 } 00595 00602 void 00603 DDS::del_var(const string &n) 00604 { 00605 if( d_container ) 00606 { 00607 d_container->del_var( n ) ; 00608 return ; 00609 } 00610 00611 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00612 if ((*i)->name() == n) { 00613 BaseType *bt = *i ; 00614 vars.erase(i) ; 00615 delete bt ; bt = 0; 00616 return; 00617 } 00618 } 00619 } 00620 00625 void 00626 DDS::del_var(Vars_iter i) 00627 { 00628 if (i != vars.end()) { 00629 BaseType *bt = *i ; 00630 vars.erase(i) ; 00631 delete bt ; bt = 0; 00632 } 00633 } 00634 00641 void 00642 DDS::del_var(Vars_iter i1, Vars_iter i2) 00643 { 00644 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) { 00645 BaseType *bt = *i_tmp ; 00646 delete bt ; bt = 0; 00647 } 00648 vars.erase(i1, i2) ; 00649 } 00650 00658 BaseType * 00659 DDS::var(const string &n, BaseType::btp_stack &s) 00660 { 00661 return var(n, &s); 00662 } 00682 BaseType * 00683 DDS::var(const string &n, BaseType::btp_stack *s) 00684 { 00685 string name = www2id(n); 00686 if( d_container ) 00687 return d_container->var( name, false, s ) ; 00688 00689 BaseType *v = exact_match(name, s); 00690 if (v) 00691 return v; 00692 00693 return leaf_match(name, s); 00694 } 00695 00696 BaseType * 00697 DDS::leaf_match(const string &n, BaseType::btp_stack *s) 00698 { 00699 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl); 00700 00701 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00702 BaseType *btp = *i; 00703 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl); 00704 // Look for the name in the dataset's top-level 00705 if (btp->name() == n) { 00706 DBG(cerr << "Found " << n << " in: " << btp->name() << endl); 00707 return btp; 00708 } 00709 00710 if (btp->is_constructor_type()) { 00711 BaseType *found = btp->var(n, false, s); 00712 if (found) { 00713 DBG(cerr << "Found " << n << " in: " << btp->name() << endl); 00714 return found; 00715 } 00716 } 00717 #if STRUCTURE_ARRAY_SYNTAX_OLD 00718 if (btp->is_vector_type() && btp->var()->is_constructor_type()) { 00719 s->push(btp); 00720 BaseType *found = btp->var()->var(n, false, s); 00721 if (found) { 00722 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl); 00723 return found; 00724 } 00725 } 00726 #endif 00727 } 00728 00729 return 0; // It is not here. 00730 } 00731 00732 BaseType * 00733 DDS::exact_match(const string &name, BaseType::btp_stack *s) 00734 { 00735 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00736 BaseType *btp = *i; 00737 DBG2(cerr << "Looking for " << name << " in: " << btp << endl); 00738 // Look for the name in the current ctor type or the top level 00739 if (btp->name() == name) { 00740 DBG2(cerr << "Found " << name << " in: " << btp << endl); 00741 return btp; 00742 } 00743 } 00744 00745 string::size_type dot_pos = name.find("."); 00746 if (dot_pos != string::npos) { 00747 string aggregate = name.substr(0, dot_pos); 00748 string field = name.substr(dot_pos + 1); 00749 00750 BaseType *agg_ptr = var(aggregate, s); 00751 if (agg_ptr) { 00752 DBG2(cerr << "Descending into " << agg_ptr->name() << endl); 00753 return agg_ptr->var(field, true, s); 00754 } 00755 else 00756 return 0; // qualified names must be *fully* qualified 00757 } 00758 00759 return 0; // It is not here. 00760 } 00761 00762 00765 DDS::Vars_iter 00766 DDS::var_begin() 00767 { 00768 return vars.begin(); 00769 } 00770 00771 DDS::Vars_riter 00772 DDS::var_rbegin() 00773 { 00774 return vars.rbegin(); 00775 } 00776 00777 DDS::Vars_iter 00778 DDS::var_end() 00779 { 00780 return vars.end() ; 00781 } 00782 00783 DDS::Vars_riter 00784 DDS::var_rend() 00785 { 00786 return vars.rend() ; 00787 } 00788 00792 DDS::Vars_iter 00793 DDS::get_vars_iter(int i) 00794 { 00795 return vars.begin() + i; 00796 } 00797 00801 BaseType * 00802 DDS::get_var_index(int i) 00803 { 00804 return *(vars.begin() + i); 00805 } 00806 00808 int 00809 DDS::num_var() 00810 { 00811 return vars.size(); 00812 } 00813 00814 void 00815 DDS::timeout_on() 00816 { 00817 #ifndef WIN32 00818 alarm(d_timeout); 00819 #endif 00820 } 00821 00822 void 00823 DDS::timeout_off() 00824 { 00825 #ifndef WIN32 00826 d_timeout = alarm(0); 00827 #endif 00828 } 00829 00830 void 00831 DDS::set_timeout(int t) 00832 { 00833 // Has no effect under win32 00834 d_timeout = t; 00835 } 00836 00837 int 00838 DDS::get_timeout() 00839 { 00840 // Has to effect under win32 00841 return d_timeout; 00842 } 00843 00845 void 00846 DDS::tag_nested_sequences() 00847 { 00848 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00849 if ((*i)->type() == dods_sequence_c) 00850 dynamic_cast<Sequence&>(**i).set_leaf_sequence(); 00851 else if ((*i)->type() == dods_structure_c) 00852 dynamic_cast<Structure&>(**i).set_leaf_sequence(); 00853 } 00854 } 00855 00857 void 00858 DDS::parse(string fname) 00859 { 00860 FILE *in = fopen(fname.c_str(), "r"); 00861 00862 if (!in) { 00863 throw Error(cannot_read_file, "Could not open: " + fname); 00864 } 00865 00866 try { 00867 parse(in); 00868 fclose(in); 00869 } 00870 catch (Error &e) { 00871 fclose(in); 00872 throw e; 00873 } 00874 } 00875 00876 00878 void 00879 DDS::parse(int fd) 00880 { 00881 #ifdef WIN32 00882 FILE *in = fdopen(_dup(fd), "r"); 00883 #else 00884 FILE *in = fdopen(dup(fd), "r"); 00885 #endif 00886 00887 if (!in) { 00888 throw InternalErr(__FILE__, __LINE__, "Could not access file."); 00889 } 00890 00891 try { 00892 parse(in); 00893 fclose(in); 00894 } 00895 catch (Error &e) { 00896 fclose(in); 00897 throw e; 00898 } 00899 } 00900 00907 void 00908 DDS::parse(FILE *in) 00909 { 00910 if (!in) { 00911 throw InternalErr(__FILE__, __LINE__, "Null input stream."); 00912 } 00913 00914 void *buffer = dds_buffer(in); 00915 dds_switch_to_buffer(buffer); 00916 00917 parser_arg arg(this); 00918 00919 bool status = ddsparse((void *) & arg) == 0; 00920 00921 dds_delete_buffer(buffer); 00922 00923 DBG2(cout << "Status from parser: " << status << endl); 00924 00925 // STATUS is the result of the parser function; if a recoverable error 00926 // was found it will be true but arg.status() will be false. 00927 if (!status || !arg.status()) {// Check parse result 00928 if (arg.error()) 00929 throw *arg.error(); 00930 } 00931 } 00932 00933 #if FILE_METHODS 00934 00935 void 00936 DDS::print(FILE *out) 00937 { 00938 #if 0 00939 ostringstream oss; 00940 print(oss); 00941 00942 fwrite(oss.str().c_str(), oss.str().length(), 1, out); 00943 #else 00944 fprintf(out, "Dataset {\n") ; 00945 00946 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00947 (*i)->print_decl(out) ; 00948 } 00949 00950 fprintf(out, "} %s;\n", id2www(name).c_str()) ; 00951 00952 return ; 00953 #endif 00954 } 00955 #endif 00956 00958 void 00959 DDS::print(ostream &out) 00960 { 00961 out << "Dataset {\n" ; 00962 00963 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00964 (*i)->print_decl(out) ; 00965 } 00966 00967 out << "} " << id2www(name) << ";\n" ; 00968 00969 return ; 00970 } 00971 00972 #if FILE_METHODS 00973 00983 void 00984 DDS::print_constrained(FILE *out) 00985 { 00986 fprintf(out, "Dataset {\n") ; 00987 00988 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 00989 // for each variable, indent with four spaces, print a trailing 00990 // semicolon, do not print debugging information, print only 00991 // variables in the current projection. 00992 (*i)->print_decl(out, " ", true, false, true) ; 00993 } 00994 00995 fprintf(out, "} %s;\n", id2www(name).c_str()) ; 00996 00997 return; 00998 } 00999 #endif 01000 01011 void 01012 DDS::print_constrained(ostream &out) 01013 { 01014 out << "Dataset {\n" ; 01015 01016 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 01017 // for each variable, indent with four spaces, print a trailing 01018 // semicolon, do not print debugging information, print only 01019 // variables in the current projection. 01020 (*i)->print_decl(out, " ", true, false, true) ; 01021 } 01022 01023 out << "} " << id2www(name) << ";\n" ; 01024 01025 return; 01026 } 01027 01028 #if FILE_METHODS 01029 class VariablePrintXML : public unary_function<BaseType *, void> 01030 { 01031 FILE *d_out; 01032 bool d_constrained; 01033 public: 01034 VariablePrintXML(FILE *out, bool constrained) 01035 : d_out(out), d_constrained(constrained) 01036 {} 01037 void operator()(BaseType *bt) 01038 { 01039 bt->print_xml(d_out, " ", d_constrained); 01040 } 01041 }; 01042 01053 void 01054 DDS::print_xml(FILE *out, bool constrained, const string &blob) 01055 { 01056 fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 01057 01058 fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str()); 01059 01060 fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"); 01061 01062 fprintf(out,"method=\"FILE*\"\n"); 01063 fprintf(out, "dap_major=\"%d\"\n", get_dap_major()); 01064 fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor()); 01065 01066 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 01067 // this at some point... jhrg 01068 if (get_dap_major() == 3 && get_dap_minor() == 2) { 01069 fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str()); 01070 01071 fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n", 01072 c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str()); 01073 } 01074 else { 01075 fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str()); 01076 fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n", 01077 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str()); 01078 } 01079 01080 01081 d_attr.print_xml(out, " ", constrained); 01082 01083 fprintf(out, "\n"); 01084 01085 for_each(var_begin(), var_end(), VariablePrintXML(out, constrained)); 01086 01087 fprintf(out, "\n"); 01088 01089 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 01090 // the same. jhrg 01091 if (get_dap_major() == 2 && get_dap_minor() == 0) { 01092 fprintf(out, " <dataBLOB href=\"\"/>\n"); 01093 } 01094 else if (!blob.empty() 01095 && (get_dap_major() == 3 && get_dap_minor() >= 2) 01096 || get_dap_major() >= 4) { 01097 fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str()); 01098 } 01099 01100 01101 fprintf(out, "</Dataset>\n"); 01102 } 01103 #endif 01104 01105 class VariablePrintXMLStrm : public unary_function<BaseType *, void> 01106 { 01107 ostream &d_out; 01108 bool d_constrained; 01109 public: 01110 VariablePrintXMLStrm(ostream &out, bool constrained) 01111 : d_out(out), d_constrained(constrained) 01112 {} 01113 void operator()(BaseType *bt) 01114 { 01115 bt->print_xml(d_out, " ", d_constrained); 01116 } 01117 }; 01118 01129 void 01130 DDS::print_xml(ostream &out, bool constrained, const string &blob) 01131 { 01132 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ; 01133 01134 out << "<Dataset name=\"" << id2xml(name) << "\"\n" ; 01135 01136 out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ; 01137 01138 // Are we responding to a 3.2 or 2.0 client? We will have to improve on 01139 // this at some point... jhrg 01140 if (get_dap_major() == 3 && get_dap_minor() == 2) { 01141 out << "xsi:schemaLocation=\"" << c_dap32_namespace 01142 << " " << c_default_dap32_schema_location << "\"\n" ; 01143 01144 out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n"; 01145 out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n"; 01146 01147 out << "xmlns=\"" << c_dap32_namespace << "\"\n" ; 01148 out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ; 01149 01150 out << "dapVersion=\"" << get_dap_major() << "." 01151 << get_dap_minor() << "\""; 01152 01153 if (!get_request_xml_base().empty()) { 01154 out << "\n"; 01155 out << "xmlns:xml=\"" << c_xml_namespace << "\"\n"; 01156 out << "xml:base=\"" << get_request_xml_base() << "\""; 01157 } 01158 01159 // Close the Dataset element 01160 out << ">\n"; 01161 } 01162 else { 01163 out << "xmlns=\"" << c_dap20_namespace << "\"\n" ; 01164 out << "xsi:schemaLocation=\"" << c_dap20_namespace 01165 << " " << c_default_dap20_schema_location << "\">\n\n" ; 01166 } 01167 01168 d_attr.print_xml(out, " ", constrained); 01169 01170 out << "\n" ; 01171 01172 for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained)); 01173 01174 out << "\n" ; 01175 01176 // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially 01177 // the same. 01178 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is 01179 // actually the CID of the MIME part that holds the data. 01180 if (get_dap_major() == 2 && get_dap_minor() == 0) { 01181 out << " <dataBLOB href=\"\"/>\n" ; 01182 } 01183 else if (!blob.empty() 01184 && (get_dap_major() == 3 && get_dap_minor() >= 2) 01185 || get_dap_major() >= 4) { 01186 out << " <blob href=\"cid:" << blob << "\"/>\n"; 01187 } 01188 01189 out << "</Dataset>\n" ; 01190 } 01191 01192 // Used by DDS::send() when returning data from a function call. 01207 bool 01208 DDS::check_semantics(bool all) 01209 { 01210 // The dataset must have a name 01211 if (name == "") { 01212 cerr << "A dataset must have a name" << endl; 01213 return false; 01214 } 01215 01216 string msg; 01217 if (!unique_names(vars, name, "Dataset", msg)) 01218 return false; 01219 01220 if (all) 01221 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01222 if (!(*i)->check_semantics(msg, true)) 01223 return false; 01224 01225 return true; 01226 } 01227 01253 bool 01254 DDS::mark(const string &n, bool state) 01255 { 01256 BaseType::btp_stack *s = new BaseType::btp_stack; 01257 01258 DBG2(cerr << "DDS::mark: Looking for " << n << endl); 01259 01260 BaseType *variable = var(n, s); 01261 if (!variable) { 01262 DBG2(cerr << "Could not find variable " << n << endl); 01263 delete s; s = 0; 01264 return false; 01265 } 01266 variable->set_send_p(state); 01267 01268 DBG2(cerr << "DDS::mark: Set variable " << variable->name() 01269 << " (a " << variable->type_name() << ")" << endl); 01270 01271 // Now check the btp_stack and run BaseType::set_send_p for every 01272 // BaseType pointer on the stack. Using BaseType::set_send_p() will 01273 // set the property for a Constructor but not its contained variables 01274 // which preserves the semantics of projecting just one field. 01275 while (!s->empty()) { 01276 s->top()->BaseType::set_send_p(state); 01277 01278 DBG2(cerr << "DDS::mark: Set variable " << s->top()->name() 01279 << " (a " << s->top()->type_name() << ")" << endl); 01280 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none"; 01281 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none"; 01282 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl); 01283 01284 s->pop(); 01285 } 01286 01287 delete s ; s = 0; 01288 01289 return true; 01290 } 01291 01297 void 01298 DDS::mark_all(bool state) 01299 { 01300 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01301 (*i)->set_send_p(state); 01302 } 01303 01311 void 01312 DDS::dump(ostream &strm) const 01313 { 01314 strm << DapIndent::LMarg << "DDS::dump - (" 01315 << (void *)this << ")" << endl ; 01316 DapIndent::Indent() ; 01317 strm << DapIndent::LMarg << "name: " << name << endl ; 01318 strm << DapIndent::LMarg << "filename: " << d_filename << endl ; 01319 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl; 01320 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl; 01321 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ; 01322 01323 strm << DapIndent::LMarg << "global attributes:" << endl ; 01324 DapIndent::Indent() ; 01325 d_attr.dump(strm) ; 01326 DapIndent::UnIndent() ; 01327 01328 if (vars.size()) { 01329 strm << DapIndent::LMarg << "vars:" << endl ; 01330 DapIndent::Indent() ; 01331 Vars_citer i = vars.begin() ; 01332 Vars_citer ie = vars.end() ; 01333 for (; i != ie; i++) { 01334 (*i)->dump(strm) ; 01335 } 01336 DapIndent::UnIndent() ; 01337 } 01338 else { 01339 strm << DapIndent::LMarg << "vars: none" << endl ; 01340 } 01341 01342 DapIndent::UnIndent() ; 01343 } 01344 01345 } // namespace libdap