libdap Updated for version 3.20.8
libdap4 is an implementation of OPeNDAP's DAP protocol.
DDS.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31//
32// jhrg 9/7/94
33
34#include "config.h"
35
36#include <cstdio>
37#include <cmath>
38#include <climits>
39#include <cstdint>
40
41#include <sys/types.h>
42
43#ifdef WIN32
44#include <io.h>
45#include <process.h>
46#include <fstream>
47#else
48#include <unistd.h> // for alarm and dup
49#include <sys/wait.h>
50#endif
51
52#include <iostream>
53#include <sstream>
54#include <algorithm>
55#include <functional>
56#include <memory>
57
58// #define DODS_DEBUG
59// #define DODS_DEBUG2
60
61#include "GNURegex.h"
62
63#include "DAS.h"
64#include "Clause.h"
65#include "Error.h"
66#include "InternalErr.h"
67#if 0
68#include "Keywords2.h"
69#endif
70
71#include "parser.h"
72#include "debug.h"
73#include "util.h"
74#include "DapIndent.h"
75
76#include "Byte.h"
77#include "Int16.h"
78#include "UInt16.h"
79#include "Int32.h"
80#include "UInt32.h"
81#include "Float32.h"
82#include "Float64.h"
83#include "Str.h"
84#include "Url.h"
85#include "Array.h"
86#include "Structure.h"
87#include "Sequence.h"
88#include "Grid.h"
89
90#include "escaping.h"
91
97const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
98const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
99
100const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
101
102const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
103const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
104const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
105
106const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
107const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
108const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
109
110const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
111const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
112const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
113
117const string TOP_LEVEL_ATTRS_CONTAINER_NAME = "DAP4_GLOBAL";
118
119using namespace std;
120
121int ddsparse(libdap::parser_arg *arg);
122
123// Glue for the DDS parser defined in dds.lex
124void dds_switch_to_buffer(void *new_buffer);
125void dds_delete_buffer(void * buffer);
126void *dds_buffer(FILE *fp);
127
128namespace libdap {
129
130void
131DDS::duplicate(const DDS &dds)
132{
133 DBG(cerr << "Entering DDS::duplicate... " <<endl);
134#if 0
135 BaseTypeFactory *d_factory;
136
137 string d_name; // The dataset d_name
138 string d_filename; // File d_name (or other OS identifier) for
139 string d_container_name; // d_name of container structure
140 Structure *d_container; // current container for container d_name
141 // dataset or part of dataset.
142
143 int d_dap_major; // The protocol major version number
144 int d_dap_minor; // ... and minor version number
145 string d_dap_version; // String version of the protocol
146 string d_request_xml_base;
147 string d_namespace;
148
149 AttrTable d_attr; // Global attributes.
150
151 vector<BaseType *> vars; // Variables at the top level
152
153 int d_timeout; // alarm time in seconds. If greater than
154 // zero, raise the alarm signal if more than
155 // d_timeout seconds are spent reading data.
156 Keywords d_keywords; // Holds keywords parsed from the CE
157
158 long d_max_response_size; // In bytes
159#endif
160
161 d_factory = dds.d_factory;
162
163 d_name = dds.d_name;
164 d_filename = dds.d_filename;
165 d_container_name = dds.d_container_name;
166 d_container = dds.d_container;
167
168 d_dap_major = dds.d_dap_major;
169 d_dap_minor = dds.d_dap_minor;
170
171 d_dap_version = dds.d_dap_version; // String version of the protocol
172 d_request_xml_base = dds.d_request_xml_base;
173 d_namespace = dds.d_namespace;
174
175 d_attr = dds.d_attr;
176
177 DDS &dds_tmp = const_cast<DDS &>(dds);
178
179 // copy the things pointed to by the list, not just the pointers
180 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
181 add_var(*i); // add_var() dups the BaseType.
182 }
183
184 d_timeout = dds.d_timeout;
185
186#if 0
187 d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
188#endif
189
190 d_max_response_size_kb = dds.d_max_response_size_kb;
191}
192
205DDS::DDS(BaseTypeFactory *factory, const string &name)
206 : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
207 d_request_xml_base(""),
208 d_timeout(0), /*d_keywords(),*/ d_max_response_size_kb(0)
209{
210 DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
211
212 // This method sets a number of values, including those returned by
213 // get_protocol_major(), ..., get_namespace().
214 set_dap_version("2.0");
215}
216
232DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
233 : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
234 d_request_xml_base(""),
235 d_timeout(0), /*d_keywords(),*/ d_max_response_size_kb(0)
236{
237 DBG(cerr << "Building a DDS for version: " << version << endl);
238
239 // This method sets a number of values, including those returned by
240 // get_protocol_major(), ..., get_namespace().
241 set_dap_version(version);
242}
243
245DDS::DDS(const DDS &rhs) : DapObj()
246{
247 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
248 duplicate(rhs);
249 DBG(cerr << " bye." << endl);
250}
251
252DDS::~DDS()
253{
254 // delete all the variables in this DDS
255 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
256 BaseType *btp = *i ;
257 delete btp ; btp = 0;
258 }
259}
260
261DDS &
262DDS::operator=(const DDS &rhs)
263{
264 DBG(cerr << "Entering DDS::operator= ..." << endl);
265 if (this == &rhs)
266 return *this;
267
268 duplicate(rhs);
269
270 DBG(cerr << " bye." << endl);
271 return *this;
272}
273
288{
289 // If there is a container set in the DDS then check the container from
290 // the DAS. If they are not the same container, then throw an exception
291 // (should be working on the same container). If the container does not
292 // exist in the DAS, then throw an exception
293 if (d_container && das->container_name() != d_container_name)
294 throw InternalErr(__FILE__, __LINE__,
295 "Error transferring attributes: working on a container in dds, but not das");
296
297 // Give each variable a chance to claim its attributes.
299
300 for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
301 (*i)->transfer_attributes(top);
302 }
303#if 0
304 Vars_iter var = var_begin();
305 while (var != var_end()) {
306 try {
307 DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl);
308 (*var)->transfer_attributes(top);
309 var++;
310 }
311 catch (Error &e) {
312 DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
313 var++;
314 throw e;
315 }
316 }
317#endif
318 // Now we transfer all of the attributes still marked as global to the
319 // global container in the DDS.
320 for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
321 if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
322 // copy the source container so that the DAS passed in can be
323 // deleted after calling this method.
324 AttrTable *at = new AttrTable(*(*i)->attributes);
325 d_attr.append_container(at, at->get_name());
326 }
327 }
328#if 0
329 AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
330 while (at_cont_p != top_level->attr_end()) {
331 // In truth, all of the top level attributes should be containers, but
332 // this test handles the abnormal case where somehow someone makes a
333 // top level attribute that is not a container by silently dropping it.
334 if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
335 DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl);
336 // copy the source container so that the DAS passed in can be
337 // deleted after calling this method.
338 AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
339 d_attr.append_container(at, at->get_name());
340 }
341
342 at_cont_p++;
343 }
344#endif
345}
346
354
356string
358{
359 return d_name;
360}
361
363void
364DDS::set_dataset_name(const string &n)
365{
366 d_name = n;
367}
368
370
372AttrTable &
374{
375 return d_attr;
376}
377
387string
389{
390 return d_filename;
391}
392
394void
395DDS::filename(const string &fn)
396{
397 d_filename = fn;
398}
400
404void
406{
407 d_dap_major = p;
408
409 // This works because regardless of the order set_dap_major and set_dap_minor
410 // are called, once they both are called, the value in the string is
411 // correct. I protect against negative numbers because that would be
412 // nonsensical.
413 if (d_dap_minor >= 0) {
414 ostringstream oss;
415 oss << d_dap_major << "." << d_dap_minor;
416 d_dap_version = oss.str();
417 }
418}
419
423void
425{
426 d_dap_minor = p;
427
428 if (d_dap_major >= 0) {
429 ostringstream oss;
430 oss << d_dap_major << "." << d_dap_minor;
431 d_dap_version = oss.str();
432 }
433}
434
440void
441DDS::set_dap_version(const string &v /* = "2.0" */)
442{
443 istringstream iss(v);
444
445 int major = -1, minor = -1;
446 char dot;
447 if (!iss.eof() && !iss.fail())
448 iss >> major;
449 if (!iss.eof() && !iss.fail())
450 iss >> dot;
451 if (!iss.eof() && !iss.fail())
452 iss >> minor;
453
454 if (major == -1 || minor == -1 or dot != '.')
455 throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
456
457 d_dap_version = v;
458
459 d_dap_major = major;
460 d_dap_minor = minor;
461
462 // Now set the related XML constants. These might be overwritten if
463 // the DDS instance is being built from a document parse, but if it's
464 // being constructed by a server the code to generate the XML document
465 // needs these values to match the DAP version information.
466 switch (d_dap_major) {
467 case 2:
468 d_namespace = c_dap20_namespace;
469 break;
470 case 3:
471 d_namespace = c_dap32_namespace;
472 break;
473 case 4:
474 d_namespace = c_dap40_namespace;
475 break;
476 default:
477 throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
478 }
479}
480
488void
490{
491 int major = floor(d);
492 int minor = (d-major)*10;
493
494 DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
495
496 ostringstream oss;
497 oss << major << "." << minor;
498
499 set_dap_version(oss.str());
500}
501
511string
513{
514 return d_container_name;
515}
516
519void
520DDS::container_name(const string &cn)
521{
522 // we want to search the DDS for the top level structure with the given
523 // d_name. Set the container to null so that we don't search some previous
524 // container.
525 d_container = 0 ;
526 if( !cn.empty() )
527 {
528 d_container = dynamic_cast<Structure *>( var( cn ) ) ;
529 if( !d_container )
530 {
531 // create a structure for this container. Calling add_var
532 // while_container is null will add the new structure to DDS and
533 // not some sub structure. Adding the new structure makes a copy
534 // of it. So after adding it, go get it and set d_container.
535 Structure *s = new Structure( cn ) ;
536 add_var( s ) ;
537 delete s ;
538 s = 0 ;
539 d_container = dynamic_cast<Structure *>( var( cn ) ) ;
540 }
541 }
542 d_container_name = cn;
543
544}
545
547Structure *
549{
550 return d_container ;
551}
552
554
565[[deprecated("Use DDS::get_request_size_kb()")]]
566int DDS::get_request_size(bool constrained)
567{
568 int w = 0;
569 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
570 if (constrained) {
571 if ((*i)->send_p())
572 w += (*i)->width(constrained);
573 }
574 else {
575 w += (*i)->width(constrained);
576 }
577 }
578 return w;
579}
580
593uint64_t DDS::get_request_size_kb(bool constrained)
594{
595 uint64_t req_size = 0;
596 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
597 if (constrained) {
598 if ((*i)->send_p())
599 req_size += (*i)->width(constrained);
600 }
601 else {
602 req_size += (*i)->width(constrained);
603 }
604 }
605 return req_size/1024;
606}
607
608
615 if (!bt)
616 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
617#if 0
618 if (bt->is_dap4_only_type())
619 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
620#endif
621 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
622
623 BaseType *btp = bt->ptr_duplicate();
624 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
625 if (d_container) {
626 // Mem leak fix [mjohnson nov 2009]
627 // Structure::add_var() creates ANOTHER copy.
628 d_container->add_var(bt);
629 // So we need to delete btp or else it leaks
630 delete btp;
631 btp = 0;
632 }
633 else {
634 vars.push_back(btp);
635 }
636}
637
640void
642{
643 if (!bt)
644 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
645
646 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
647
648 if (d_container) {
649 d_container->add_var_nocopy(bt);
650 }
651 else {
652 vars.push_back(bt);
653 }
654}
655
656
663void
664DDS::del_var(const string &n)
665{
666 if( d_container )
667 {
668 d_container->del_var( n ) ;
669 return ;
670 }
671
672 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
673 if ((*i)->name() == n) {
674 BaseType *bt = *i ;
675 vars.erase(i) ;
676 delete bt ; bt = 0;
677 return;
678 }
679 }
680}
681
686void
687DDS::del_var(Vars_iter i)
688{
689 if (i != vars.end()) {
690 BaseType *bt = *i ;
691 vars.erase(i) ;
692 delete bt ; bt = 0;
693 }
694}
695
702void
703DDS::del_var(Vars_iter i1, Vars_iter i2)
704{
705 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
706 BaseType *bt = *i_tmp ;
707 delete bt ; bt = 0;
708 }
709 vars.erase(i1, i2) ;
710}
711
719BaseType *
720DDS::var(const string &n, BaseType::btp_stack &s)
721{
722 return var(n, &s);
723}
743BaseType *
744DDS::var(const string &n, BaseType::btp_stack *s)
745{
746 string name = www2id(n);
747 if( d_container )
748 return d_container->var( name, false, s ) ;
749
750 BaseType *v = exact_match(name, s);
751 if (v)
752 return v;
753
754 return leaf_match(name, s);
755}
756
757BaseType *
758DDS::leaf_match(const string &n, BaseType::btp_stack *s)
759{
760 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
761
762 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
763 BaseType *btp = *i;
764 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
765 // Look for the d_name in the dataset's top-level
766 if (btp->name() == n) {
767 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
768 return btp;
769 }
770
771 if (btp->is_constructor_type()) {
772 BaseType *found = btp->var(n, false, s);
773 if (found) {
774 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
775 return found;
776 }
777 }
778#if STRUCTURE_ARRAY_SYNTAX_OLD
779 if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
780 s->push(btp);
781 BaseType *found = btp->var()->var(n, false, s);
782 if (found) {
783 DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
784 return found;
785 }
786 }
787#endif
788 }
789
790 return 0; // It is not here.
791}
792
793BaseType *
794DDS::exact_match(const string &name, BaseType::btp_stack *s)
795{
796 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
797 BaseType *btp = *i;
798 DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
799 // Look for the d_name in the current ctor type or the top level
800 if (btp->name() == name) {
801 DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
802 return btp;
803 }
804 }
805
806 string::size_type dot_pos = name.find(".");
807 if (dot_pos != string::npos) {
808 string aggregate = name.substr(0, dot_pos);
809 string field = name.substr(dot_pos + 1);
810
811 BaseType *agg_ptr = var(aggregate, s);
812 if (agg_ptr) {
813 DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
814 return agg_ptr->var(field, true, s);
815 }
816 else
817 return 0; // qualified names must be *fully* qualified
818 }
819
820 return 0; // It is not here.
821}
822
823
826DDS::Vars_iter
828{
829 return vars.begin();
830}
831
832DDS::Vars_riter
834{
835 return vars.rbegin();
836}
837
838DDS::Vars_iter
840{
841 return vars.end() ;
842}
843
844DDS::Vars_riter
846{
847 return vars.rend() ;
848}
849
853DDS::Vars_iter
855{
856 return vars.begin() + i;
857}
858
862BaseType *
864{
865 return *(vars.begin() + i);
866}
867
872void
873DDS::insert_var(Vars_iter i, BaseType *ptr)
874{
875#if 0
876 if (ptr->is_dap4_only_type())
877 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
878#endif
879 vars.insert(i, ptr->ptr_duplicate());
880}
881
889void
891{
892#if 0
893 if (ptr->is_dap4_only_type())
894 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
895#endif
896 vars.insert(i, ptr);
897}
898
900int
902{
903 return vars.size();
904}
905
906void
907DDS::timeout_on()
908{
909#if USE_LOCAL_TIMEOUT_SCHEME
910#ifndef WIN32
911 alarm(d_timeout);
912#endif
913#endif
914}
915
916void
917DDS::timeout_off()
918{
919#if USE_LOCAL_TIMEOUT_SCHEME
920#ifndef WIN32
921 // Old behavior commented out. I think it is an error to change the value
922 // of d_timeout. The way this will likely be used is to set the timeout
923 // value once and then 'turn on' or turn off' that timeout as the situation
924 // dictates. The initeded use for the DDS timeout is so that timeouts for
925 // data responses will include the CPU resources needed to build the response
926 // but not the time spent transmitting the response. This may change when
927 // more parallelism is added to the server... These methods are called from
928 // BESDapResponseBuilder in bes/dap. jhrg 12/22/15
929
930 // d_timeout = alarm(0);
931
932 alarm(0);
933#endif
934#endif
935}
936
937void
938DDS::set_timeout(int)
939{
940#if USE_LOCAL_TIMEOUT_SCHEME
941 // Has no effect under win32
942 d_timeout = t;
943#endif
944}
945
946int
947DDS::get_timeout()
948{
949#if USE_LOCAL_TIMEOUT_SCHEME
950 // Has to effect under win32
951 return d_timeout;
952#endif
953 return 0;
954}
955
957void
959{
960 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
961 if ((*i)->type() == dods_sequence_c)
962 dynamic_cast<Sequence&>(**i).set_leaf_sequence();
963 else if ((*i)->type() == dods_structure_c)
964 dynamic_cast<Structure&>(**i).set_leaf_sequence();
965 }
966}
967
969void
970DDS::parse(string fname)
971{
972 FILE *in = fopen(fname.c_str(), "r");
973
974 if (!in) {
975 throw Error(cannot_read_file, "Could not open: " + fname);
976 }
977
978 try {
979 parse(in);
980 fclose(in);
981 }
982 catch (Error &e) {
983 fclose(in);
984 throw ;
985 }
986}
987
988
990void
992{
993#ifdef WIN32
994 int new_fd = _dup(fd);
995#else
996 int new_fd = dup(fd);
997#endif
998
999 if (new_fd < 0)
1000 throw InternalErr(__FILE__, __LINE__, "Could not access file.");
1001 FILE *in = fdopen(new_fd, "r");
1002
1003 if (!in) {
1004 throw InternalErr(__FILE__, __LINE__, "Could not access file.");
1005 }
1006
1007 try {
1008 parse(in);
1009 fclose(in);
1010 }
1011 catch (Error &e) {
1012 fclose(in);
1013 throw ;
1014 }
1015}
1016
1023void
1024DDS::parse(FILE *in)
1025{
1026 if (!in) {
1027 throw InternalErr(__FILE__, __LINE__, "Null input stream.");
1028 }
1029
1030 void *buffer = dds_buffer(in);
1031 dds_switch_to_buffer(buffer);
1032
1033 parser_arg arg(this);
1034
1035 bool status = ddsparse(&arg) == 0;
1036
1037 dds_delete_buffer(buffer);
1038
1039 DBG2(cout << "Status from parser: " << status << endl);
1040
1041 // STATUS is the result of the parser function; if a recoverable error
1042 // was found it will be true but arg.status() will be false.
1043 if (!status || !arg.status()) {// Check parse result
1044 if (arg.error())
1045 throw *arg.error();
1046 }
1047}
1048
1050void
1051DDS::print(FILE *out)
1052{
1053 ostringstream oss;
1054 print(oss);
1055 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1056}
1057
1059void
1060DDS::print(ostream &out)
1061{
1062 out << "Dataset {\n" ;
1063
1064 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1065 (*i)->print_decl(out) ;
1066 }
1067
1068 out << "} " << id2www(d_name) << ";\n" ;
1069
1070 return ;
1071}
1072
1080bool
1082{
1083 for (AttrTable::Attr_iter i = a.attr_begin(), e = a.attr_end(); i != e; ++i) {
1084 if (a.get_attr_type(i) != Attr_container) {
1085 return true;
1086 }
1087 else if (has_dap2_attributes(*a.get_attr_table(i))) {
1088 return true;
1089 }
1090 }
1091
1092 return false;
1093
1094#if 0
1095 vector<AttrTable*> tables;
1096
1097 for (AttrTable::Attr_iter i = a.attr_begin(), e = a.attr_end(); i != e; ++i) {
1098 if (a.get_attr_type(i) != Attr_container)
1099 return true;
1100 else
1101 tables.push_back(a.get_attr_table(i));
1102 }
1103
1104 bool it_does = false;
1105 for (vector<AttrTable*>::iterartor i = tables.begin(), e = tables.end(); it_does || i != e; ++i) {
1106 it_does = has_dap2_attributes(**i);
1107 }
1108
1109 return it_does;
1110#endif
1111}
1112
1120bool
1122{
1124 return true;
1125 }
1126
1127 Constructor *cons = dynamic_cast<Constructor *>(btp);
1128 if (cons) {
1129 Grid* grid = dynamic_cast<Grid*>(btp);
1130 if(grid){
1131 return has_dap2_attributes(grid->get_array());
1132 }
1133 else {
1134 for (Constructor::Vars_iter i = cons->var_begin(), e = cons->var_end(); i != e; i++) {
1135 if (has_dap2_attributes(*i)) return true;
1136 }
1137 }
1138 }
1139 return false;
1140}
1141
1151static string four_spaces = " ";
1152void print_var_das(ostream &out, BaseType *bt, string indent = "") {
1153
1154 if (!has_dap2_attributes(bt))
1155 return;
1156
1157 AttrTable attr_table = bt->get_attr_table();
1158 out << indent << add_space_encoding(bt->name()) << " {" << endl;
1159
1160 Constructor *cnstrctr = dynamic_cast<Constructor *>(bt);
1161 if (cnstrctr) {
1162 Grid *grid = dynamic_cast<Grid *>(bt);
1163 if (grid) {
1164 Array *gridArray = grid->get_array();
1165 AttrTable arrayAT = gridArray->get_attr_table();
1166
1167 if (has_dap2_attributes(gridArray))
1168 gridArray->get_attr_table().print(out, indent + four_spaces);
1169#if 0
1170 // I dropped this because we don't want the MAP vectors showing up in the DAS
1171 // as children of a Grid (aka flatten the Grid bro) - ndp 5/25/18
1172 for (Grid::Map_iter mIter = grid->map_begin();
1173 mIter != grid->map_end(); ++mIter) {
1174 BaseType *currentMap = *mIter;
1175 if (has_dap2_attributes(currentMap))
1176 print_var_das(out, currentMap, indent + four_spaces);
1177 }
1178#endif
1179 }
1180 else {
1181 attr_table.print(out, indent + four_spaces);
1182 Constructor::Vars_iter i = cnstrctr->var_begin();
1183 Constructor::Vars_iter e = cnstrctr->var_end();
1184 for (; i != e; i++) {
1185 // Only call print_var_das() if there really are attributes.
1186 // This is made complicated because while there might be none
1187 // for a particular var (*i), that var might be a ctor and its
1188 // descendant might have an attribute. jhrg 3/18/18
1189 if (has_dap2_attributes(*i))
1190 print_var_das(out, *i, indent + four_spaces);
1191 }
1192 }
1193 }
1194 else {
1195 attr_table.print(out, indent + four_spaces);
1196 }
1197
1198 out << indent << "}" << endl;
1199}
1200
1209void
1210DDS::print_das(ostream &out)
1211{
1212#if 0
1213 string indent(" ");
1214 out << "Attributes {" << endl;
1215 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1216 if (has_dap2_attributes(*i))
1217 print_var_das(out, *i, four_spaces);
1218 }
1219 // Print the global attributes at the end.
1220 d_attr.print(out,indent);
1221 out << "}" << endl;
1222#endif
1223
1224 auto_ptr<DAS> das(get_das());
1225
1226 das->print(out);
1227}
1228
1238DAS *
1240{
1241 DAS *das = new DAS();
1242 get_das(das);
1243 return das;
1244}
1245
1251static string
1252get_unique_top_level_global_container_name(DAS *das)
1253{
1254 // It's virtually certain that the TOP_LEVE... name will be unique. If so,
1255 // return the name. The code tests for a table to see if the name _should not_ be used.
1256 AttrTable *table = das->get_table(TOP_LEVEL_ATTRS_CONTAINER_NAME);
1257 if (!table)
1258 return TOP_LEVEL_ATTRS_CONTAINER_NAME;
1259
1260 // ... but the default name might already be used
1261 unsigned int i = 0;
1262 string name;
1263 ostringstream oss;
1264 while (table) {
1265 oss.str(""); // reset to empty for the next suffix
1266 oss << "_" << ++i;
1267 if (!(i < UINT_MAX))
1268 throw InternalErr(__FILE__, __LINE__, "Cannot add top-level attributes to the DAS");
1269 name = TOP_LEVEL_ATTRS_CONTAINER_NAME + oss.str();
1270 table = das->get_table(name);
1271 }
1272
1273 return name;
1274}
1275
1284 Constructor *cons = dynamic_cast<Constructor *>(bt);
1285 if (cons) {
1286 Grid *grid = dynamic_cast<Grid *>(bt);
1287 if(grid){
1288 Array *gridArray = grid->get_array();
1289 AttrTable arrayAT = gridArray->get_attr_table();
1290
1291 for( AttrTable::Attr_iter atIter = arrayAT.attr_begin(); atIter!=arrayAT.attr_end(); ++atIter){
1292 AttrType type = arrayAT.get_attr_type(atIter);
1293 string childName = arrayAT.get_name(atIter);
1294 if (type == Attr_container){
1295 at->append_container( new AttrTable(*arrayAT.get_attr_table(atIter)), childName);
1296 }
1297 else {
1298 vector<string>* pAttrTokens = arrayAT.get_attr_vector(atIter);
1299 // append_attr makes a copy of the vector, so we don't have to do so here.
1300 at->append_attr(childName, AttrType_to_String(type), pAttrTokens);
1301 }
1302 }
1303
1304 }
1305 else {
1306 for (Constructor::Vars_iter i = cons->var_begin(), e = cons->var_end(); i != e; i++) {
1307 if (has_dap2_attributes(*i)) {
1308 AttrTable *childAttrT = new AttrTable((*i)->get_attr_table());
1309 fillConstructorAttrTable(childAttrT, *i);
1310 at->append_container(childAttrT,(*i)->name());
1311 }
1312 }
1313 }
1314 }
1315}
1316
1317void DDS::get_das(DAS *das)
1318{
1319 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1320 if (has_dap2_attributes(*i)) {
1321 AttrTable *childAttrT = new AttrTable((*i)->get_attr_table());
1322 fillConstructorAttrTable(childAttrT, *i);
1323 das->add_table((*i)->name(), childAttrT);
1324 }
1325 }
1326
1327 // Used in the rare case we have global attributes not in a table.
1328 auto_ptr<AttrTable> global(new AttrTable);
1329
1330 for (AttrTable::Attr_iter i = d_attr.attr_begin(); i != d_attr.attr_end(); ++i) {
1331 // It's possible, given the API and if the DDS was built from a DMR, that a
1332 // global attribute might not be a container; check for that.
1333 if (d_attr.get_attr_table(i)) {
1334 das->add_table(d_attr.get_name(i), new AttrTable(*(d_attr.get_attr_table(i))));
1335 }
1336 else {
1337 // This must be a top level attribute outside a container. jhrg 4/6/18
1338 global->append_attr(d_attr.get_name(i), d_attr.get_type(i), d_attr.get_attr_vector(i));
1339 }
1340 }
1341
1342 // if any attributes were added to 'global,' add it to the DAS and take control of the pointer.
1343 if (global->get_size() > 0) {
1344 das->add_table(get_unique_top_level_global_container_name(das), global.get()); // What if this name is not unique?
1345 global.release();
1346 }
1347}
1348
1359void
1361{
1362 ostringstream oss;
1363 print_constrained(oss);
1364 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1365}
1366
1377void
1379{
1380 out << "Dataset {\n" ;
1381
1382 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1383 // for each variable, indent with four spaces, print a trailing
1384 // semicolon, do not print debugging information, print only
1385 // variables in the current projection.
1386 (*i)->print_decl(out, " ", true, false, true) ;
1387 }
1388
1389 out << "} " << id2www(d_name) << ";\n" ;
1390
1391 return;
1392}
1393
1405void
1406DDS::print_xml(FILE *out, bool constrained, const string &blob)
1407{
1408 ostringstream oss;
1409 print_xml_writer(oss, constrained, blob);
1410 fwrite(oss.str().data(), 1, oss.str().length(), out);
1411}
1412
1424void
1425DDS::print_xml(ostream &out, bool constrained, const string &blob)
1426{
1427 print_xml_writer(out, constrained, blob);
1428}
1429
1430class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1431{
1432 XMLWriter &d_xml;
1433 bool d_constrained;
1434public:
1435 VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
1436 : d_xml(xml), d_constrained(constrained)
1437 {}
1438 void operator()(BaseType *bt)
1439 {
1440 bt->print_xml_writer(d_xml, d_constrained);
1441 }
1442};
1443
1460void
1461DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
1462{
1463 XMLWriter xml(" ");
1464
1465 // this is the old version of this method. It produced different output for
1466 // different version of DAP. We stopped using version numbers and use different
1467 // web api calls (DMR, DAP for DAP4 and DAS, DDS and DODS for DAP2) so the
1468 // dap version numbers are old and should not be used. There also seems to
1469 // be a bug where these version numbers change 'randomly' but which doesn't
1470 // show up in testing (or with valgrind or asan). jhrg 9/10/18
1471#if 0
1472 // Stamp and repeat for these sections; trying to economize is makes it
1473 // even more confusing
1474 if (get_dap_major() >= 4) {
1475 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1476 throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1477 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1478 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1479
1480 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0)
1481 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1482
1483 if (!get_request_xml_base().empty()) {
1484 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1485 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1486
1487 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1488 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1489 }
1490 if (!get_namespace().empty()) {
1491 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0)
1492 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1493 }
1494 }
1495 else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
1496 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1497 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1498 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1499 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1500 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1501 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1502
1503 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1504 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1505
1506 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1507 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1508
1509 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1510 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1511
1512 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1513 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1514 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1515 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1516
1517 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1518 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1519
1520 if (!get_request_xml_base().empty()) {
1521 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1522 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1523
1524 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1525 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1526 }
1527 }
1528 else { // dap2
1529 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1530 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1531 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1532 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1533 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1534 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1535
1536 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1537 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1538
1539 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1540 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1541 }
1542#endif
1543
1544#if DAP2_DDX
1545 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1546 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1547 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1548 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1549 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1550 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1551
1552 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1553 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1554
1555 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1556 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1557#elif DAP3_2_DDX
1558 // This is the 'DAP 3.2' DDX response - now the only response libdap will return.
1559 // jhrg 9/10/18
1560 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1561 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1562 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1563 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1564 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1565 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1566
1567 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1568 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1569
1570 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1571 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1572
1573 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1574 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1575
1576 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1577 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1578 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1579 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1580
1581 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1582 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1583
1584 if (!get_request_xml_base().empty()) {
1585 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1586 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1587
1588 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1589 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1590 }
1591#else
1592#error Must define DAP2_DDX or DAP3_2_DDX
1593#endif
1594
1595 // Print the global attributes
1596 d_attr.print_xml_writer(xml);
1597
1598 // Print each variable
1599 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1600
1601 // As above, this method now onl returns the DAP 3.2 version of the DDX response.
1602 // jhrg 9/10/28
1603#if 0
1604 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1605 // the CID of the MIME part that holds the data. For DAP2 (which includes
1606 // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
1607 // given.
1608 if (get_dap_major() >= 4) {
1609 if (!blob.empty()) {
1610 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1611 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1612 string cid = "cid:" + blob;
1613 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1614 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1615 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1616 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1617 }
1618 }
1619 else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
1620 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1621 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1622 string cid = "cid:" + blob;
1623 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1624 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1625 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1626 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1627 }
1628 else { // dap2
1629 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1630 throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1631 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
1632 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1633 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1634 throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
1635 }
1636#endif
1637
1638#if DAP2_DDX
1639 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1640 throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1641 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
1642 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1643 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1644 throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
1645#elif DAP3_2_DDX
1646 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1647 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1648 string cid = "cid:" + blob;
1649 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1650 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1651 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1652 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1653
1654 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1655 throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
1656#else
1657#error Must define DAP2_DDX or DAP3_2_DDX
1658#endif
1659
1660 out << xml.get_doc();// << ends;// << endl;
1661}
1662
1676void
1677DDS::print_dmr(ostream &out, bool constrained)
1678{
1679 if (get_dap_major() < 4)
1680 throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
1681
1682 XMLWriter xml(" ");
1683
1684 // DAP4 wraps a dataset in a top-level Group element.
1685 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1686 throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1687
1688 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
1689 (const xmlChar*) c_xml_namespace.c_str()) < 0)
1690 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1691
1692 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
1693 < 0)
1694 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1695
1696 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
1697 (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
1698 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1699
1700 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
1701 (const xmlChar*) get_namespace().c_str()) < 0)
1702 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1703
1704 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
1705 (const xmlChar*) get_dap_version().c_str()) < 0)
1706 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1707
1708 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
1709 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1710
1711 if (!get_request_xml_base().empty()) {
1712 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
1713 (const xmlChar*) get_request_xml_base().c_str()) < 0)
1714 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1715 }
1716
1717 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
1718 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1719
1720 // Print the global attributes
1721 d_attr.print_xml_writer(xml);
1722
1723 // Print each variable
1724 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1725
1726 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1727 throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
1728
1729 out << xml.get_doc();
1730}
1731
1732// Used by DDS::send() when returning data from a function call.
1747bool
1749{
1750 // The dataset must have a d_name
1751 if (d_name == "") {
1752 cerr << "A dataset must have a d_name" << endl;
1753 return false;
1754 }
1755
1756 string msg;
1757 if (!unique_names(vars, d_name, "Dataset", msg))
1758 return false;
1759
1760 if (all)
1761 for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1762 if (!(*i)->check_semantics(msg, true))
1763 return false;
1764
1765 return true;
1766}
1767
1791bool
1792DDS::mark(const string &n, bool state)
1793{
1794#if 0
1795 // TODO use auto_ptr
1796 BaseType::btp_stack *s = new BaseType::btp_stack;
1797#endif
1798
1799 auto_ptr<BaseType::btp_stack> s(new BaseType::btp_stack);
1800
1801 DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1802
1803 BaseType *variable = var(n, s.get());
1804 if (!variable) {
1805 throw Error(malformed_expr, "Could not find variable " + n);
1806#if 0
1807 DBG2(cerr << "Could not find variable " << n << endl);
1808#if 0
1809 delete s; s = 0;
1810#endif
1811 return false;
1812#endif
1813 }
1814 variable->set_send_p(state);
1815
1816 DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
1817 << " (a " << variable->type_name() << ")" << endl);
1818
1819 // Now check the btp_stack and run BaseType::set_send_p for every
1820 // BaseType pointer on the stack. Using BaseType::set_send_p() will
1821 // set the property for a Constructor but not its contained variables
1822 // which preserves the semantics of projecting just one field.
1823 while (!s->empty()) {
1824 s->top()->BaseType::set_send_p(state);
1825
1826 DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
1827 << " (a " << s->top()->type_name() << ")" << endl);
1828
1829 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1830 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1831 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1832
1833 s->pop();
1834 }
1835
1836#if 0
1837 delete s; s = 0;
1838#endif
1839
1840 return true;
1841}
1842
1848void
1849DDS::mark_all(bool state)
1850{
1851 for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1852 (*i)->set_send_p(state);
1853}
1854
1862void
1863DDS::dump(ostream &strm) const
1864{
1865 strm << DapIndent::LMarg << "DDS::dump - ("
1866 << (void *)this << ")" << endl ;
1867 DapIndent::Indent() ;
1868 strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
1869 strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1870 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1871 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1872 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1873
1874 strm << DapIndent::LMarg << "global attributes:" << endl ;
1875 DapIndent::Indent() ;
1876 d_attr.dump(strm) ;
1877 DapIndent::UnIndent() ;
1878
1879 if (vars.size()) {
1880 strm << DapIndent::LMarg << "vars:" << endl ;
1881 DapIndent::Indent() ;
1882 Vars_citer i = vars.begin() ;
1883 Vars_citer ie = vars.end() ;
1884 for (; i != ie; i++) {
1885 (*i)->dump(strm) ;
1886 }
1887 DapIndent::UnIndent() ;
1888 }
1889 else {
1890 strm << DapIndent::LMarg << "vars: none" << endl ;
1891 }
1892
1893 DapIndent::UnIndent() ;
1894}
1895
1896} // namespace libdap
A multidimensional array of identical data types.
Definition Array.h:113
Contains the attributes for a dataset.
Definition AttrTable.h:143
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:410
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:607
virtual Attr_iter attr_end()
Definition AttrTable.cc:719
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:653
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:307
virtual Attr_iter attr_begin()
Definition AttrTable.cc:711
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:238
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition AttrTable.cc:231
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition AttrTable.cc:621
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:379
virtual AttrTable & get_attr_table()
Definition BaseType.cc:582
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:320
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Returns a pointer to a member of a constructor class.
Definition BaseType.cc:758
virtual bool is_vector_type() const
Returns true if the instance is a vector (i.e., array) type variable.
Definition BaseType.cc:402
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable.
Definition BaseType.cc:412
virtual void set_send_p(bool state)
Definition BaseType.cc:568
virtual BaseType * ptr_duplicate()=0
virtual unsigned int width(bool constrained=false) const
Vars_iter var_begin()
Hold attribute data for a DAP2 dataset.
Definition DAS.h:122
virtual AttrTable * get_top_level_attributes()
Returns the top most set of attributes.
Definition DAS.h:166
AttrTable * get_table(AttrTable::Attr_iter &i)
Returns the referenced variable attribute table.
Definition DAS.cc:179
virtual string container_name() const
Returns the name of the current attribute container when multiple files used to build this DAS.
Definition DAS.h:149
void set_dataset_name(const string &n)
Definition DDS.cc:364
void set_dap_major(int p)
Definition DDS.cc:405
void mark_all(bool state)
Definition DDS.cc:1849
void print_dmr(ostream &out, bool constrained)
Print the DAP4 DMR object using a DDS.
Definition DDS.cc:1677
Vars_riter var_rend()
Return a reverse iterator.
Definition DDS.cc:845
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition DDS.cc:641
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition DDS.cc:1748
string filename() const
Definition DDS.cc:388
virtual AttrTable & get_attr_table()
Definition DDS.cc:373
uint64_t get_request_size_kb(bool constrained)
Get the estimated response size in kilobytes.
Definition DDS.cc:593
virtual void transfer_attributes(DAS *das)
Definition DDS.cc:287
void set_dap_minor(int p)
Definition DDS.cc:424
Vars_riter var_rbegin()
Return a reverse iterator.
Definition DDS.cc:833
string get_namespace() const
Get the namespace associated with the DDS - likely set only by DDX responses.
Definition DDS.h:292
int num_var()
Returns the number of variables in the DDS.
Definition DDS.cc:901
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition DDS.cc:854
void print(FILE *out)
Print the entire DDS to the specified file.
Definition DDS.cc:1051
BaseType * get_var_index(int i)
Get a variable.
Definition DDS.cc:863
int get_request_size(bool constrained)
Get the estimated response size in bytes.
Definition DDS.cc:566
string get_dataset_name() const
Definition DDS.cc:357
void del_var(const string &n)
Removes a variable from the DDS.
Definition DDS.cc:664
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition DDS.cc:970
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition DDS.cc:720
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition DDS.cc:1406
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition DDS.cc:873
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition DDS.cc:1792
int get_dap_minor() const
Get the DAP minor version as sent by the client.
Definition DDS.h:268
DDS(BaseTypeFactory *factory, const string &name="")
Definition DDS.cc:205
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition DDS.cc:958
DAS * get_das()
Get a DAS object.
Definition DDS.cc:1239
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition DDS.cc:1360
Vars_iter var_begin()
Return an iterator to the first variable.
Definition DDS.cc:827
string container_name()
Definition DDS.cc:512
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition DDS.cc:890
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition DDS.h:286
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition DDS.h:266
Vars_iter var_end()
Return an iterator.
Definition DDS.cc:839
void set_dap_version(const string &version_string="2.0")
Definition DDS.cc:441
Structure * container()
Definition DDS.cc:548
void add_var(BaseType *bt)
Adds a copy of the variable to the DDS. Using the ptr_duplicate() method, perform a deep copy on the ...
Definition DDS.cc:614
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition DDS.cc:1461
void print_das(ostream &out)
write the DAS response given the attribute information in the DDS
Definition DDS.cc:1210
virtual void dump(ostream &strm) const
dumps information about this object
Definition DDS.cc:1863
libdap base object for common functionality of libdap objects
Definition DapObj.h:51
A class for error processing.
Definition Error.h:94
std::string get_error_message() const
Definition Error.cc:243
Holds the Grid data type.
Definition Grid.h:123
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition Grid.cc:518
A class for software fault reporting.
Definition InternalErr.h:65
Holds a sequence.
Definition Sequence.h:163
virtual void set_leaf_sequence(int lvl=1)
Mark the Sequence which holds the leaf elements.
Definition Sequence.cc:1236
Holds a structure (aggregate) type.
Definition Structure.h:84
virtual void set_leaf_sequence(int level=1)
Traverse Structure, set Sequence leaf nodes.
Definition Structure.cc:331
top level DAP object to house generic methods
bool has_dap2_attributes(AttrTable &a)
Definition DDS.cc:1081
string www2id(const string &in, const string &escape, const string &except)
Definition escaping.cc:220
string add_space_encoding(const string &s)
Definition AttrTable.cc:78
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:97
void fillConstructorAttrTable(AttrTable *at, BaseType *bt)
Recursive helper function for Building DAS entries for Constructor types.
Definition DDS.cc:1283
string id2www(string in, const string &allowable)
Definition escaping.cc:153
Pass parameters by reference to a parser.
Definition parser.h:69