libdap
Updated for version 3.17.0
|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #include <cstdio> 00037 #include <cmath> 00038 #include <sys/types.h> 00039 00040 #ifdef WIN32 00041 #include <io.h> 00042 #include <process.h> 00043 #include <fstream> 00044 #else 00045 #include <unistd.h> // for alarm and dup 00046 #include <sys/wait.h> 00047 #endif 00048 00049 #include <iostream> 00050 #include <sstream> 00051 #include <algorithm> 00052 #include <functional> 00053 00054 //#define DODS_DEBUG 00055 //#define DODS_DEBUG2 00056 00057 #include "GNURegex.h" 00058 00059 #include "DAS.h" 00060 #include "Clause.h" 00061 #include "Error.h" 00062 #include "InternalErr.h" 00063 #include "Keywords2.h" 00064 00065 #include "parser.h" 00066 #include "debug.h" 00067 #include "util.h" 00068 00069 #include "Byte.h" 00070 #include "Int16.h" 00071 #include "UInt16.h" 00072 #include "Int32.h" 00073 #include "UInt32.h" 00074 #include "Float32.h" 00075 #include "Float64.h" 00076 #include "Str.h" 00077 #include "Url.h" 00078 #include "Array.h" 00079 #include "Structure.h" 00080 #include "Sequence.h" 00081 #include "Grid.h" 00082 00083 #include "escaping.h" 00084 00095 const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance"; 00096 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace"; 00097 00098 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl"; 00099 00100 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd"; 00101 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd"; 00102 const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd"; 00103 00104 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2"; 00105 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#"; 00106 const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#"; 00107 00108 const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location; 00109 const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location; 00110 const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location; 00121 using namespace std; 00122 00123 int ddsparse(libdap::parser_arg *arg); 00124 00125 // Glue for the DDS parser defined in dds.lex 00126 void dds_switch_to_buffer(void *new_buffer); 00127 void dds_delete_buffer(void * buffer); 00128 void *dds_buffer(FILE *fp); 00129 00130 namespace libdap { 00131 00132 void 00133 DDS::duplicate(const DDS &dds) 00134 { 00135 DBG(cerr << "Entering DDS::duplicate... " <<endl); 00136 #if 0 00137 BaseTypeFactory *d_factory; 00138 00139 string d_name; // The dataset d_name 00140 string d_filename; // File d_name (or other OS identifier) for 00141 string d_container_name; // d_name of container structure 00142 Structure *d_container; // current container for container d_name 00143 // dataset or part of dataset. 00144 00145 int d_dap_major; // The protocol major version number 00146 int d_dap_minor; // ... and minor version number 00147 string d_dap_version; // String version of the protocol 00148 string d_request_xml_base; 00149 string d_namespace; 00150 00151 AttrTable d_attr; // Global attributes. 00152 00153 vector<BaseType *> vars; // Variables at the top level 00154 00155 int d_timeout; // alarm time in seconds. If greater than 00156 // zero, raise the alarm signal if more than 00157 // d_timeout seconds are spent reading data. 00158 Keywords d_keywords; // Holds keywords parsed from the CE 00159 00160 long d_max_response_size; // In bytes 00161 #endif 00162 00163 d_factory = dds.d_factory; 00164 00165 d_name = dds.d_name; 00166 d_filename = dds.d_filename; 00167 d_container_name = dds.d_container_name; 00168 d_container = dds.d_container; 00169 00170 d_dap_major = dds.d_dap_major; 00171 d_dap_minor = dds.d_dap_minor; 00172 00173 d_dap_version = dds.d_dap_version; // String version of the protocol 00174 d_request_xml_base = dds.d_request_xml_base; 00175 d_namespace = dds.d_namespace; 00176 00177 d_attr = dds.d_attr; 00178 00179 DDS &dds_tmp = const_cast<DDS &>(dds); 00180 00181 // copy the things pointed to by the list, not just the pointers 00182 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) { 00183 add_var(*i); // add_var() dups the BaseType. 00184 } 00185 00186 d_timeout = dds.d_timeout; 00187 00188 d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers 00189 00190 d_max_response_size = dds.d_max_response_size; 00191 } 00192 00205 DDS::DDS(BaseTypeFactory *factory, const string &name) 00206 : d_factory(factory), d_name(name), d_container_name(""), d_container(0), 00207 d_request_xml_base(""), 00208 d_timeout(0), d_keywords(), d_max_response_size(0) 00209 { 00210 DBG(cerr << "Building a DDS for the default version (2.0)" << endl); 00211 00212 // This method sets a number of values, including those returned by 00213 // get_protocol_major(), ..., get_namespace(). 00214 set_dap_version("2.0"); 00215 } 00216 00232 DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version) 00233 : d_factory(factory), d_name(name), d_container_name(""), d_container(0), 00234 d_request_xml_base(""), 00235 d_timeout(0), d_keywords(), d_max_response_size(0) 00236 { 00237 DBG(cerr << "Building a DDS for version: " << version << endl); 00238 00239 // This method sets a number of values, including those returned by 00240 // get_protocol_major(), ..., get_namespace(). 00241 set_dap_version(version); 00242 } 00243 00245 DDS::DDS(const DDS &rhs) : DapObj() 00246 { 00247 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl); 00248 duplicate(rhs); 00249 DBG(cerr << " bye." << endl); 00250 } 00251 00252 DDS::~DDS() 00253 { 00254 // delete all the variables in this DDS 00255 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00256 BaseType *btp = *i ; 00257 delete btp ; btp = 0; 00258 } 00259 } 00260 00261 DDS & 00262 DDS::operator=(const DDS &rhs) 00263 { 00264 DBG(cerr << "Entering DDS::operator= ..." << endl); 00265 if (this == &rhs) 00266 return *this; 00267 00268 duplicate(rhs); 00269 00270 DBG(cerr << " bye." << endl); 00271 return *this; 00272 } 00273 00287 void DDS::transfer_attributes(DAS *das) 00288 { 00289 // If there is a container set in the DDS then check the container from 00290 // the DAS. If they are not the same container, then throw an exception 00291 // (should be working on the same container). If the container does not 00292 // exist in the DAS, then throw an exception 00293 if (d_container && das->container_name() != d_container_name) 00294 throw InternalErr(__FILE__, __LINE__, 00295 "Error transferring attributes: working on a container in dds, but not das"); 00296 00297 // Give each variable a chance to claim its attributes. 00298 AttrTable *top = das->get_top_level_attributes(); 00299 00300 for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) { 00301 (*i)->transfer_attributes(top); 00302 } 00303 #if 0 00304 Vars_iter var = var_begin(); 00305 while (var != var_end()) { 00306 try { 00307 DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl); 00308 (*var)->transfer_attributes(top); 00309 var++; 00310 } 00311 catch (Error &e) { 00312 DBG(cerr << "Got this exception: " << e.get_error_message() << endl); 00313 var++; 00314 throw e; 00315 } 00316 } 00317 #endif 00318 // Now we transfer all of the attributes still marked as global to the 00319 // global container in the DDS. 00320 for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) { 00321 if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) { 00322 // copy the source container so that the DAS passed in can be 00323 // deleted after calling this method. 00324 AttrTable *at = new AttrTable(*(*i)->attributes); 00325 d_attr.append_container(at, at->get_name()); 00326 } 00327 } 00328 #if 0 00329 AttrTable::Attr_iter at_cont_p = top_level->attr_begin(); 00330 while (at_cont_p != top_level->attr_end()) { 00331 // In truth, all of the top level attributes should be containers, but 00332 // this test handles the abnormal case where somehow someone makes a 00333 // top level attribute that is not a container by silently dropping it. 00334 if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) { 00335 DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl); 00336 // copy the source container so that the DAS passed in can be 00337 // deleted after calling this method. 00338 AttrTable *at = new AttrTable(*(*at_cont_p)->attributes); 00339 d_attr.append_container(at, at->get_name()); 00340 } 00341 00342 at_cont_p++; 00343 } 00344 #endif 00345 } 00346 00354 00356 string 00357 DDS::get_dataset_name() const 00358 { 00359 return d_name; 00360 } 00361 00363 void 00364 DDS::set_dataset_name(const string &n) 00365 { 00366 d_name = n; 00367 } 00368 00370 00372 AttrTable & 00373 DDS::get_attr_table() 00374 { 00375 return d_attr; 00376 } 00377 00387 string 00388 DDS::filename() const 00389 { 00390 return d_filename; 00391 } 00392 00394 void 00395 DDS::filename(const string &fn) 00396 { 00397 d_filename = fn; 00398 } 00400 00404 void 00405 DDS::set_dap_major(int p) 00406 { 00407 d_dap_major = p; 00408 00409 // This works because regardless of the order set_dap_major and set_dap_minor 00410 // are called, once they both are called, the value in the string is 00411 // correct. I protect against negative numbers because that would be 00412 // nonsensical. 00413 if (d_dap_minor >= 0) { 00414 ostringstream oss; 00415 oss << d_dap_major << "." << d_dap_minor; 00416 d_dap_version = oss.str(); 00417 } 00418 } 00419 00423 void 00424 DDS::set_dap_minor(int p) 00425 { 00426 d_dap_minor = p; 00427 00428 if (d_dap_major >= 0) { 00429 ostringstream oss; 00430 oss << d_dap_major << "." << d_dap_minor; 00431 d_dap_version = oss.str(); 00432 } 00433 } 00434 00440 void 00441 DDS::set_dap_version(const string &v /* = "2.0" */) 00442 { 00443 istringstream iss(v); 00444 00445 int major = -1, minor = -1; 00446 char dot; 00447 if (!iss.eof() && !iss.fail()) 00448 iss >> major; 00449 if (!iss.eof() && !iss.fail()) 00450 iss >> dot; 00451 if (!iss.eof() && !iss.fail()) 00452 iss >> minor; 00453 00454 if (major == -1 || minor == -1 or dot != '.') 00455 throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v); 00456 00457 d_dap_version = v; 00458 00459 d_dap_major = major; 00460 d_dap_minor = minor; 00461 00462 // Now set the related XML constants. These might be overwritten if 00463 // the DDS instance is being built from a document parse, but if it's 00464 // being constructed by a server the code to generate the XML document 00465 // needs these values to match the DAP version information. 00466 switch (d_dap_major) { 00467 case 2: 00468 d_namespace = c_dap20_namespace; 00469 break; 00470 case 3: 00471 d_namespace = c_dap32_namespace; 00472 break; 00473 case 4: 00474 d_namespace = c_dap40_namespace; 00475 break; 00476 default: 00477 throw InternalErr(__FILE__, __LINE__, "Unknown DAP version."); 00478 } 00479 } 00480 00488 void 00489 DDS::set_dap_version(double d) 00490 { 00491 int major = floor(d); 00492 int minor = (d-major)*10; 00493 00494 DBG(cerr << "Major: " << major << ", Minor: " << minor << endl); 00495 00496 ostringstream oss; 00497 oss << major << "." << minor; 00498 00499 set_dap_version(oss.str()); 00500 } 00501 00511 string 00512 DDS::container_name() 00513 { 00514 return d_container_name; 00515 } 00516 00519 void 00520 DDS::container_name(const string &cn) 00521 { 00522 // we want to search the DDS for the top level structure with the given 00523 // d_name. Set the container to null so that we don't search some previous 00524 // container. 00525 d_container = 0 ; 00526 if( !cn.empty() ) 00527 { 00528 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00529 if( !d_container ) 00530 { 00531 // create a structure for this container. Calling add_var 00532 // while_container is null will add the new structure to DDS and 00533 // not some sub structure. Adding the new structure makes a copy 00534 // of it. So after adding it, go get it and set d_container. 00535 Structure *s = new Structure( cn ) ; 00536 add_var( s ) ; 00537 delete s ; 00538 s = 0 ; 00539 d_container = dynamic_cast<Structure *>( var( cn ) ) ; 00540 } 00541 } 00542 d_container_name = cn; 00543 00544 } 00545 00547 Structure * 00548 DDS::container() 00549 { 00550 return d_container ; 00551 } 00552 00554 00565 int 00566 DDS::get_request_size(bool constrained) 00567 { 00568 int w = 0; 00569 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00570 if (constrained) { 00571 if ((*i)->send_p()) 00572 w += (*i)->width(constrained); 00573 } 00574 else { 00575 w += (*i)->width(constrained); 00576 } 00577 } 00578 00579 return w; 00580 } 00581 00587 void DDS::add_var(BaseType *bt) { 00588 if (!bt) 00589 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer."); 00590 #if 0 00591 if (bt->is_dap4_only_type()) 00592 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS."); 00593 #endif 00594 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl); 00595 00596 BaseType *btp = bt->ptr_duplicate(); 00597 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl); 00598 if (d_container) { 00599 // Mem leak fix [mjohnson nov 2009] 00600 // Structure::add_var() creates ANOTHER copy. 00601 d_container->add_var(bt); 00602 // So we need to delete btp or else it leaks 00603 delete btp; 00604 btp = 0; 00605 } 00606 else { 00607 vars.push_back(btp); 00608 } 00609 } 00610 00613 void 00614 DDS::add_var_nocopy(BaseType *bt) 00615 { 00616 if (!bt) 00617 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer."); 00618 #if 0 00619 //FIXME There's no longer a DAP2 and DAP4 DDS 00620 if (bt->is_dap4_only_type()) 00621 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS."); 00622 #endif 00623 00624 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl); 00625 00626 if (d_container) { 00627 d_container->add_var_nocopy(bt); 00628 } 00629 else { 00630 vars.push_back(bt); 00631 } 00632 } 00633 00634 00641 void 00642 DDS::del_var(const string &n) 00643 { 00644 if( d_container ) 00645 { 00646 d_container->del_var( n ) ; 00647 return ; 00648 } 00649 00650 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00651 if ((*i)->name() == n) { 00652 BaseType *bt = *i ; 00653 vars.erase(i) ; 00654 delete bt ; bt = 0; 00655 return; 00656 } 00657 } 00658 } 00659 00664 void 00665 DDS::del_var(Vars_iter i) 00666 { 00667 if (i != vars.end()) { 00668 BaseType *bt = *i ; 00669 vars.erase(i) ; 00670 delete bt ; bt = 0; 00671 } 00672 } 00673 00680 void 00681 DDS::del_var(Vars_iter i1, Vars_iter i2) 00682 { 00683 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) { 00684 BaseType *bt = *i_tmp ; 00685 delete bt ; bt = 0; 00686 } 00687 vars.erase(i1, i2) ; 00688 } 00689 00697 BaseType * 00698 DDS::var(const string &n, BaseType::btp_stack &s) 00699 { 00700 return var(n, &s); 00701 } 00721 BaseType * 00722 DDS::var(const string &n, BaseType::btp_stack *s) 00723 { 00724 string name = www2id(n); 00725 if( d_container ) 00726 return d_container->var( name, false, s ) ; 00727 00728 BaseType *v = exact_match(name, s); 00729 if (v) 00730 return v; 00731 00732 return leaf_match(name, s); 00733 } 00734 00735 BaseType * 00736 DDS::leaf_match(const string &n, BaseType::btp_stack *s) 00737 { 00738 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl); 00739 00740 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00741 BaseType *btp = *i; 00742 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->d_name() << endl); 00743 // Look for the d_name in the dataset's top-level 00744 if (btp->name() == n) { 00745 DBG(cerr << "Found " << n << " in: " << btp->d_name() << endl); 00746 return btp; 00747 } 00748 00749 if (btp->is_constructor_type()) { 00750 BaseType *found = btp->var(n, false, s); 00751 if (found) { 00752 DBG(cerr << "Found " << n << " in: " << btp->d_name() << endl); 00753 return found; 00754 } 00755 } 00756 #if STRUCTURE_ARRAY_SYNTAX_OLD 00757 if (btp->is_vector_type() && btp->var()->is_constructor_type()) { 00758 s->push(btp); 00759 BaseType *found = btp->var()->var(n, false, s); 00760 if (found) { 00761 DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl); 00762 return found; 00763 } 00764 } 00765 #endif 00766 } 00767 00768 return 0; // It is not here. 00769 } 00770 00771 BaseType * 00772 DDS::exact_match(const string &name, BaseType::btp_stack *s) 00773 { 00774 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00775 BaseType *btp = *i; 00776 DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl); 00777 // Look for the d_name in the current ctor type or the top level 00778 if (btp->name() == name) { 00779 DBG2(cerr << "Found " << d_name << " in: " << btp << endl); 00780 return btp; 00781 } 00782 } 00783 00784 string::size_type dot_pos = name.find("."); 00785 if (dot_pos != string::npos) { 00786 string aggregate = name.substr(0, dot_pos); 00787 string field = name.substr(dot_pos + 1); 00788 00789 BaseType *agg_ptr = var(aggregate, s); 00790 if (agg_ptr) { 00791 DBG2(cerr << "Descending into " << agg_ptr->name() << endl); 00792 return agg_ptr->var(field, true, s); 00793 } 00794 else 00795 return 0; // qualified names must be *fully* qualified 00796 } 00797 00798 return 0; // It is not here. 00799 } 00800 00801 00804 DDS::Vars_iter 00805 DDS::var_begin() 00806 { 00807 return vars.begin(); 00808 } 00809 00810 DDS::Vars_riter 00811 DDS::var_rbegin() 00812 { 00813 return vars.rbegin(); 00814 } 00815 00816 DDS::Vars_iter 00817 DDS::var_end() 00818 { 00819 return vars.end() ; 00820 } 00821 00822 DDS::Vars_riter 00823 DDS::var_rend() 00824 { 00825 return vars.rend() ; 00826 } 00827 00831 DDS::Vars_iter 00832 DDS::get_vars_iter(int i) 00833 { 00834 return vars.begin() + i; 00835 } 00836 00840 BaseType * 00841 DDS::get_var_index(int i) 00842 { 00843 return *(vars.begin() + i); 00844 } 00845 00850 void 00851 DDS::insert_var(Vars_iter i, BaseType *ptr) 00852 { 00853 #if 0 00854 if (ptr->is_dap4_only_type()) 00855 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS."); 00856 #endif 00857 vars.insert(i, ptr->ptr_duplicate()); 00858 } 00859 00867 void 00868 DDS::insert_var_nocopy(Vars_iter i, BaseType *ptr) 00869 { 00870 #if 0 00871 if (ptr->is_dap4_only_type()) 00872 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS."); 00873 #endif 00874 vars.insert(i, ptr); 00875 } 00876 00878 int 00879 DDS::num_var() 00880 { 00881 return vars.size(); 00882 } 00883 00884 void 00885 DDS::timeout_on() 00886 { 00887 #if USE_LOCAL_TIMEOUT_SCHEME 00888 #ifndef WIN32 00889 alarm(d_timeout); 00890 #endif 00891 #endif 00892 } 00893 00894 void 00895 DDS::timeout_off() 00896 { 00897 #if USE_LOCAL_TIMEOUT_SCHEME 00898 #ifndef WIN32 00899 // Old behavior commented out. I think it is an error to change the value 00900 // of d_timeout. The way this will likely be used is to set the timeout 00901 // value once and then 'turn on' or turn off' that timeout as the situation 00902 // dictates. The initeded use for the DDS timeout is so that timeouts for 00903 // data responses will include the CPU resources needed to build the response 00904 // but not the time spent transmitting the response. This may change when 00905 // more parallelism is added to the server... These methods are called from 00906 // BESDapResponseBuilder in bes/dap. jhrg 12/22/15 00907 00908 // d_timeout = alarm(0); 00909 00910 alarm(0); 00911 #endif 00912 #endif 00913 } 00914 00915 void 00916 DDS::set_timeout(int t) 00917 { 00918 #if USE_LOCAL_TIMEOUT_SCHEME 00919 // Has no effect under win32 00920 d_timeout = t; 00921 #endif 00922 } 00923 00924 int 00925 DDS::get_timeout() 00926 { 00927 #if USE_LOCAL_TIMEOUT_SCHEME 00928 // Has to effect under win32 00929 return d_timeout; 00930 #endif 00931 return 0; 00932 } 00933 00935 void 00936 DDS::tag_nested_sequences() 00937 { 00938 for (Vars_iter i = vars.begin(); i != vars.end(); i++) { 00939 if ((*i)->type() == dods_sequence_c) 00940 dynamic_cast<Sequence&>(**i).set_leaf_sequence(); 00941 else if ((*i)->type() == dods_structure_c) 00942 dynamic_cast<Structure&>(**i).set_leaf_sequence(); 00943 } 00944 } 00945 00947 void 00948 DDS::parse(string fname) 00949 { 00950 FILE *in = fopen(fname.c_str(), "r"); 00951 00952 if (!in) { 00953 throw Error(cannot_read_file, "Could not open: " + fname); 00954 } 00955 00956 try { 00957 parse(in); 00958 fclose(in); 00959 } 00960 catch (Error &e) { 00961 fclose(in); 00962 throw ; 00963 } 00964 } 00965 00966 00968 void 00969 DDS::parse(int fd) 00970 { 00971 #ifdef WIN32 00972 int new_fd = _dup(fd); 00973 #else 00974 int new_fd = dup(fd); 00975 #endif 00976 00977 if (new_fd < 0) 00978 throw InternalErr(__FILE__, __LINE__, "Could not access file."); 00979 FILE *in = fdopen(new_fd, "r"); 00980 00981 if (!in) { 00982 throw InternalErr(__FILE__, __LINE__, "Could not access file."); 00983 } 00984 00985 try { 00986 parse(in); 00987 fclose(in); 00988 } 00989 catch (Error &e) { 00990 fclose(in); 00991 throw ; 00992 } 00993 } 00994 01001 void 01002 DDS::parse(FILE *in) 01003 { 01004 if (!in) { 01005 throw InternalErr(__FILE__, __LINE__, "Null input stream."); 01006 } 01007 01008 void *buffer = dds_buffer(in); 01009 dds_switch_to_buffer(buffer); 01010 01011 parser_arg arg(this); 01012 01013 bool status = ddsparse(&arg) == 0; 01014 01015 dds_delete_buffer(buffer); 01016 01017 DBG2(cout << "Status from parser: " << status << endl); 01018 01019 // STATUS is the result of the parser function; if a recoverable error 01020 // was found it will be true but arg.status() will be false. 01021 if (!status || !arg.status()) {// Check parse result 01022 if (arg.error()) 01023 throw *arg.error(); 01024 } 01025 } 01026 01028 void 01029 DDS::print(FILE *out) 01030 { 01031 ostringstream oss; 01032 print(oss); 01033 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 01034 } 01035 01037 void 01038 DDS::print(ostream &out) 01039 { 01040 out << "Dataset {\n" ; 01041 01042 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 01043 (*i)->print_decl(out) ; 01044 } 01045 01046 out << "} " << id2www(d_name) << ";\n" ; 01047 01048 return ; 01049 } 01050 01060 void 01061 DDS::print_das(ostream &out) 01062 { 01063 out << "Attributes {\n" ; 01064 01065 d_attr.print(out, " "); 01066 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 01067 (*i)->get_attr_table().print(out, " "); 01068 } 01069 01070 out << "}\n" ; 01071 } 01072 01083 void 01084 DDS::print_constrained(FILE *out) 01085 { 01086 ostringstream oss; 01087 print_constrained(oss); 01088 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 01089 } 01090 01101 void 01102 DDS::print_constrained(ostream &out) 01103 { 01104 out << "Dataset {\n" ; 01105 01106 for (Vars_citer i = vars.begin(); i != vars.end(); i++) { 01107 // for each variable, indent with four spaces, print a trailing 01108 // semicolon, do not print debugging information, print only 01109 // variables in the current projection. 01110 (*i)->print_decl(out, " ", true, false, true) ; 01111 } 01112 01113 out << "} " << id2www(d_name) << ";\n" ; 01114 01115 return; 01116 } 01117 01129 void 01130 DDS::print_xml(FILE *out, bool constrained, const string &blob) 01131 { 01132 ostringstream oss; 01133 print_xml_writer(oss, constrained, blob); 01134 fwrite(oss.str().data(), 1, oss.str().length(), out); 01135 } 01136 01148 void 01149 DDS::print_xml(ostream &out, bool constrained, const string &blob) 01150 { 01151 print_xml_writer(out, constrained, blob); 01152 } 01153 01154 class VariablePrintXMLWriter : public unary_function<BaseType *, void> 01155 { 01156 XMLWriter &d_xml; 01157 bool d_constrained; 01158 public: 01159 VariablePrintXMLWriter(XMLWriter &xml, bool constrained) 01160 : d_xml(xml), d_constrained(constrained) 01161 {} 01162 void operator()(BaseType *bt) 01163 { 01164 bt->print_xml_writer(d_xml, d_constrained); 01165 } 01166 }; 01167 01184 void 01185 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob) 01186 { 01187 XMLWriter xml(" "); 01188 01189 // Stamp and repeat for these sections; trying to economize is makes it 01190 // even more confusing 01191 if (get_dap_major() >= 4) { 01192 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0) 01193 throw InternalErr(__FILE__, __LINE__, "Could not write Group element"); 01194 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0) 01195 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01196 01197 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0) 01198 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion"); 01199 01200 if (!get_request_xml_base().empty()) { 01201 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0) 01202 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml"); 01203 01204 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0) 01205 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base"); 01206 } 01207 if (!get_namespace().empty()) { 01208 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0) 01209 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns"); 01210 } 01211 } 01212 else if (get_dap_major() == 3 && get_dap_minor() >= 2) { 01213 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0) 01214 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element"); 01215 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0) 01216 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01217 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0) 01218 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi"); 01219 01220 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0) 01221 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation"); 01222 01223 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0) 01224 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl"); 01225 01226 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0) 01227 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation"); 01228 01229 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0) 01230 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns"); 01231 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0) 01232 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap"); 01233 01234 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0) 01235 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion"); 01236 01237 if (!get_request_xml_base().empty()) { 01238 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0) 01239 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml"); 01240 01241 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0) 01242 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base"); 01243 } 01244 } 01245 else { // dap2 01246 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0) 01247 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element"); 01248 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0) 01249 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name"); 01250 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0) 01251 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi"); 01252 01253 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0) 01254 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns"); 01255 01256 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0) 01257 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation"); 01258 } 01259 01260 // Print the global attributes 01261 d_attr.print_xml_writer(xml); 01262 01263 // Print each variable 01264 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained)); 01265 01266 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is 01267 // the CID of the MIME part that holds the data. For DAP2 (which includes 01268 // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's 01269 // given. 01270 if (get_dap_major() >= 4) { 01271 if (!blob.empty()) { 01272 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0) 01273 throw InternalErr(__FILE__, __LINE__, "Could not write blob element"); 01274 string cid = "cid:" + blob; 01275 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0) 01276 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name"); 01277 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01278 throw InternalErr(__FILE__, __LINE__, "Could not end blob element"); 01279 } 01280 } 01281 else if (get_dap_major() == 3 && get_dap_minor() >= 2) { 01282 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0) 01283 throw InternalErr(__FILE__, __LINE__, "Could not write blob element"); 01284 string cid = "cid:" + blob; 01285 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0) 01286 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name"); 01287 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01288 throw InternalErr(__FILE__, __LINE__, "Could not end blob element"); 01289 } 01290 else { // dap2 01291 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0) 01292 throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element"); 01293 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0) 01294 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name"); 01295 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01296 throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element"); 01297 } 01298 01299 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01300 throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element"); 01301 01302 out << xml.get_doc();// << ends;// << endl; 01303 } 01304 01317 void 01318 DDS::print_dmr(ostream &out, bool constrained) 01319 { 01320 if (get_dap_major() < 4) 01321 throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4"); 01322 01323 XMLWriter xml(" "); 01324 01325 // DAP4 wraps a dataset in a top-level Group element. 01326 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0) 01327 throw InternalErr(__FILE__, __LINE__, "Could not write Group element"); 01328 01329 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", 01330 (const xmlChar*) c_xml_namespace.c_str()) < 0) 01331 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml"); 01332 01333 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str()) 01334 < 0) 01335 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi"); 01336 01337 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", 01338 (const xmlChar*) c_dap_40_n_sl.c_str()) < 0) 01339 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation"); 01340 01341 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", 01342 (const xmlChar*) get_namespace().c_str()) < 0) 01343 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns"); 01344 01345 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", 01346 (const xmlChar*) get_dap_version().c_str()) < 0) 01347 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion"); 01348 01349 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0) 01350 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion"); 01351 01352 if (!get_request_xml_base().empty()) { 01353 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", 01354 (const xmlChar*) get_request_xml_base().c_str()) < 0) 01355 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base"); 01356 } 01357 01358 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0) 01359 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01360 01361 // Print the global attributes 01362 d_attr.print_xml_writer(xml); 01363 01364 // Print each variable 01365 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained)); 01366 01367 #if 0 01368 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is 01369 // the CID of the MIME part that holds the data. For DAP2 (which includes 01370 // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's 01371 // given. 01372 if (get_dap_major() >= 4) { 01373 if (!blob.empty()) { 01374 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0) 01375 throw InternalErr(__FILE__, __LINE__, "Could not write blob element"); 01376 string cid = "cid:" + blob; 01377 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0) 01378 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name"); 01379 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01380 throw InternalErr(__FILE__, __LINE__, "Could not end blob element"); 01381 } 01382 } 01383 #endif 01384 01385 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01386 throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element"); 01387 01388 out << xml.get_doc(); 01389 } 01390 01391 // Used by DDS::send() when returning data from a function call. 01406 bool 01407 DDS::check_semantics(bool all) 01408 { 01409 // The dataset must have a d_name 01410 if (d_name == "") { 01411 cerr << "A dataset must have a d_name" << endl; 01412 return false; 01413 } 01414 01415 string msg; 01416 if (!unique_names(vars, d_name, "Dataset", msg)) 01417 return false; 01418 01419 if (all) 01420 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01421 if (!(*i)->check_semantics(msg, true)) 01422 return false; 01423 01424 return true; 01425 } 01426 01452 bool 01453 DDS::mark(const string &n, bool state) 01454 { 01455 // TODO use auto_ptr 01456 BaseType::btp_stack *s = new BaseType::btp_stack; 01457 01458 DBG2(cerr << "DDS::mark: Looking for " << n << endl); 01459 01460 BaseType *variable = var(n, s); 01461 if (!variable) { 01462 DBG2(cerr << "Could not find variable " << n << endl); 01463 delete s; s = 0; 01464 return false; 01465 } 01466 variable->set_send_p(state); 01467 01468 DBG2(cerr << "DDS::mark: Set variable " << variable->d_name() 01469 << " (a " << variable->type_name() << ")" << endl); 01470 01471 // Now check the btp_stack and run BaseType::set_send_p for every 01472 // BaseType pointer on the stack. Using BaseType::set_send_p() will 01473 // set the property for a Constructor but not its contained variables 01474 // which preserves the semantics of projecting just one field. 01475 while (!s->empty()) { 01476 s->top()->BaseType::set_send_p(state); 01477 01478 DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name() 01479 << " (a " << s->top()->type_name() << ")" << endl); 01480 // FIXME get_parent() hosed? 01481 #if 1 01482 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none"; 01483 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none"; 01484 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl); 01485 #endif 01486 s->pop(); 01487 } 01488 01489 delete s ; s = 0; 01490 01491 return true; 01492 } 01493 01499 void 01500 DDS::mark_all(bool state) 01501 { 01502 for (Vars_iter i = vars.begin(); i != vars.end(); i++) 01503 (*i)->set_send_p(state); 01504 } 01505 01513 void 01514 DDS::dump(ostream &strm) const 01515 { 01516 strm << DapIndent::LMarg << "DDS::dump - (" 01517 << (void *)this << ")" << endl ; 01518 DapIndent::Indent() ; 01519 strm << DapIndent::LMarg << "d_name: " << d_name << endl ; 01520 strm << DapIndent::LMarg << "filename: " << d_filename << endl ; 01521 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl; 01522 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl; 01523 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ; 01524 01525 strm << DapIndent::LMarg << "global attributes:" << endl ; 01526 DapIndent::Indent() ; 01527 d_attr.dump(strm) ; 01528 DapIndent::UnIndent() ; 01529 01530 if (vars.size()) { 01531 strm << DapIndent::LMarg << "vars:" << endl ; 01532 DapIndent::Indent() ; 01533 Vars_citer i = vars.begin() ; 01534 Vars_citer ie = vars.end() ; 01535 for (; i != ie; i++) { 01536 (*i)->dump(strm) ; 01537 } 01538 DapIndent::UnIndent() ; 01539 } 01540 else { 01541 strm << DapIndent::LMarg << "vars: none" << endl ; 01542 } 01543 01544 DapIndent::UnIndent() ; 01545 } 01546 01547 } // namespace libdap