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