libdap Updated for version 3.20.5
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
40#include <sys/types.h>
41
42#ifdef WIN32
43#include <io.h>
44#include <process.h>
45#include <fstream>
46#else
47#include <unistd.h> // for alarm and dup
48#include <sys/wait.h>
49#endif
50
51#include <iostream>
52#include <sstream>
53#include <algorithm>
54#include <functional>
55#include <memory>
56
57// #define DODS_DEBUG
58// #define DODS_DEBUG2
59
60#include "GNURegex.h"
61
62#include "DAS.h"
63#include "Clause.h"
64#include "Error.h"
65#include "InternalErr.h"
66#if 0
67#include "Keywords2.h"
68#endif
69
70#include "parser.h"
71#include "debug.h"
72#include "util.h"
73#include "DapIndent.h"
74
75#include "Byte.h"
76#include "Int16.h"
77#include "UInt16.h"
78#include "Int32.h"
79#include "UInt32.h"
80#include "Float32.h"
81#include "Float64.h"
82#include "Str.h"
83#include "Url.h"
84#include "Array.h"
85#include "Structure.h"
86#include "Sequence.h"
87#include "Grid.h"
88
89#include "escaping.h"
90
96const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
97const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
98
99const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
100
101const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
102const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
103const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
104
105const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
106const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
107const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
108
109const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
110const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
111const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
112
116const string TOP_LEVEL_ATTRS_CONTAINER_NAME = "DAP4_GLOBAL";
117
118using namespace std;
119
120int ddsparse(libdap::parser_arg *arg);
121
122// Glue for the DDS parser defined in dds.lex
123void dds_switch_to_buffer(void *new_buffer);
124void dds_delete_buffer(void * buffer);
125void *dds_buffer(FILE *fp);
126
127namespace libdap {
128
129void
130DDS::duplicate(const DDS &dds)
131{
132 DBG(cerr << "Entering DDS::duplicate... " <<endl);
133#if 0
134 BaseTypeFactory *d_factory;
135
136 string d_name; // The dataset d_name
137 string d_filename; // File d_name (or other OS identifier) for
138 string d_container_name; // d_name of container structure
139 Structure *d_container; // current container for container d_name
140 // dataset or part of dataset.
141
142 int d_dap_major; // The protocol major version number
143 int d_dap_minor; // ... and minor version number
144 string d_dap_version; // String version of the protocol
145 string d_request_xml_base;
146 string d_namespace;
147
148 AttrTable d_attr; // Global attributes.
149
150 vector<BaseType *> vars; // Variables at the top level
151
152 int d_timeout; // alarm time in seconds. If greater than
153 // zero, raise the alarm signal if more than
154 // d_timeout seconds are spent reading data.
155 Keywords d_keywords; // Holds keywords parsed from the CE
156
157 long d_max_response_size; // In bytes
158#endif
159
160 d_factory = dds.d_factory;
161
162 d_name = dds.d_name;
163 d_filename = dds.d_filename;
164 d_container_name = dds.d_container_name;
165 d_container = dds.d_container;
166
167 d_dap_major = dds.d_dap_major;
168 d_dap_minor = dds.d_dap_minor;
169
170 d_dap_version = dds.d_dap_version; // String version of the protocol
171 d_request_xml_base = dds.d_request_xml_base;
172 d_namespace = dds.d_namespace;
173
174 d_attr = dds.d_attr;
175
176 DDS &dds_tmp = const_cast<DDS &>(dds);
177
178 // copy the things pointed to by the list, not just the pointers
179 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
180 add_var(*i); // add_var() dups the BaseType.
181 }
182
183 d_timeout = dds.d_timeout;
184
185#if 0
186 d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
187#endif
188
189 d_max_response_size = dds.d_max_response_size;
190}
191
204DDS::DDS(BaseTypeFactory *factory, const string &name)
205 : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
206 d_request_xml_base(""),
207 d_timeout(0), /*d_keywords(),*/ d_max_response_size(0)
208{
209 DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
210
211 // This method sets a number of values, including those returned by
212 // get_protocol_major(), ..., get_namespace().
213 set_dap_version("2.0");
214}
215
231DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
232 : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
233 d_request_xml_base(""),
234 d_timeout(0), /*d_keywords(),*/ d_max_response_size(0)
235{
236 DBG(cerr << "Building a DDS for version: " << version << endl);
237
238 // This method sets a number of values, including those returned by
239 // get_protocol_major(), ..., get_namespace().
240 set_dap_version(version);
241}
242
244DDS::DDS(const DDS &rhs) : DapObj()
245{
246 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
247 duplicate(rhs);
248 DBG(cerr << " bye." << endl);
249}
250
251DDS::~DDS()
252{
253 // delete all the variables in this DDS
254 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
255 BaseType *btp = *i ;
256 delete btp ; btp = 0;
257 }
258}
259
260DDS &
261DDS::operator=(const DDS &rhs)
262{
263 DBG(cerr << "Entering DDS::operator= ..." << endl);
264 if (this == &rhs)
265 return *this;
266
267 duplicate(rhs);
268
269 DBG(cerr << " bye." << endl);
270 return *this;
271}
272
287{
288 // If there is a container set in the DDS then check the container from
289 // the DAS. If they are not the same container, then throw an exception
290 // (should be working on the same container). If the container does not
291 // exist in the DAS, then throw an exception
292 if (d_container && das->container_name() != d_container_name)
293 throw InternalErr(__FILE__, __LINE__,
294 "Error transferring attributes: working on a container in dds, but not das");
295
296 // Give each variable a chance to claim its attributes.
298
299 for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
300 (*i)->transfer_attributes(top);
301 }
302#if 0
303 Vars_iter var = var_begin();
304 while (var != var_end()) {
305 try {
306 DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl);
307 (*var)->transfer_attributes(top);
308 var++;
309 }
310 catch (Error &e) {
311 DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
312 var++;
313 throw e;
314 }
315 }
316#endif
317 // Now we transfer all of the attributes still marked as global to the
318 // global container in the DDS.
319 for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
320 if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
321 // copy the source container so that the DAS passed in can be
322 // deleted after calling this method.
323 AttrTable *at = new AttrTable(*(*i)->attributes);
324 d_attr.append_container(at, at->get_name());
325 }
326 }
327#if 0
328 AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
329 while (at_cont_p != top_level->attr_end()) {
330 // In truth, all of the top level attributes should be containers, but
331 // this test handles the abnormal case where somehow someone makes a
332 // top level attribute that is not a container by silently dropping it.
333 if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
334 DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl);
335 // copy the source container so that the DAS passed in can be
336 // deleted after calling this method.
337 AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
338 d_attr.append_container(at, at->get_name());
339 }
340
341 at_cont_p++;
342 }
343#endif
344}
345
353
355string
357{
358 return d_name;
359}
360
362void
363DDS::set_dataset_name(const string &n)
364{
365 d_name = n;
366}
367
369
371AttrTable &
373{
374 return d_attr;
375}
376
386string
388{
389 return d_filename;
390}
391
393void
394DDS::filename(const string &fn)
395{
396 d_filename = fn;
397}
399
403void
405{
406 d_dap_major = p;
407
408 // This works because regardless of the order set_dap_major and set_dap_minor
409 // are called, once they both are called, the value in the string is
410 // correct. I protect against negative numbers because that would be
411 // nonsensical.
412 if (d_dap_minor >= 0) {
413 ostringstream oss;
414 oss << d_dap_major << "." << d_dap_minor;
415 d_dap_version = oss.str();
416 }
417}
418
422void
424{
425 d_dap_minor = p;
426
427 if (d_dap_major >= 0) {
428 ostringstream oss;
429 oss << d_dap_major << "." << d_dap_minor;
430 d_dap_version = oss.str();
431 }
432}
433
439void
440DDS::set_dap_version(const string &v /* = "2.0" */)
441{
442 istringstream iss(v);
443
444 int major = -1, minor = -1;
445 char dot;
446 if (!iss.eof() && !iss.fail())
447 iss >> major;
448 if (!iss.eof() && !iss.fail())
449 iss >> dot;
450 if (!iss.eof() && !iss.fail())
451 iss >> minor;
452
453 if (major == -1 || minor == -1 or dot != '.')
454 throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
455
456 d_dap_version = v;
457
458 d_dap_major = major;
459 d_dap_minor = minor;
460
461 // Now set the related XML constants. These might be overwritten if
462 // the DDS instance is being built from a document parse, but if it's
463 // being constructed by a server the code to generate the XML document
464 // needs these values to match the DAP version information.
465 switch (d_dap_major) {
466 case 2:
467 d_namespace = c_dap20_namespace;
468 break;
469 case 3:
470 d_namespace = c_dap32_namespace;
471 break;
472 case 4:
473 d_namespace = c_dap40_namespace;
474 break;
475 default:
476 throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
477 }
478}
479
487void
489{
490 int major = floor(d);
491 int minor = (d-major)*10;
492
493 DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
494
495 ostringstream oss;
496 oss << major << "." << minor;
497
498 set_dap_version(oss.str());
499}
500
510string
512{
513 return d_container_name;
514}
515
518void
519DDS::container_name(const string &cn)
520{
521 // we want to search the DDS for the top level structure with the given
522 // d_name. Set the container to null so that we don't search some previous
523 // container.
524 d_container = 0 ;
525 if( !cn.empty() )
526 {
527 d_container = dynamic_cast<Structure *>( var( cn ) ) ;
528 if( !d_container )
529 {
530 // create a structure for this container. Calling add_var
531 // while_container is null will add the new structure to DDS and
532 // not some sub structure. Adding the new structure makes a copy
533 // of it. So after adding it, go get it and set d_container.
534 Structure *s = new Structure( cn ) ;
535 add_var( s ) ;
536 delete s ;
537 s = 0 ;
538 d_container = dynamic_cast<Structure *>( var( cn ) ) ;
539 }
540 }
541 d_container_name = cn;
542
543}
544
546Structure *
548{
549 return d_container ;
550}
551
553
564int
565DDS::get_request_size(bool constrained)
566{
567 int w = 0;
568 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
569 if (constrained) {
570 if ((*i)->send_p())
571 w += (*i)->width(constrained);
572 }
573 else {
574 w += (*i)->width(constrained);
575 }
576 }
577
578 return w;
579}
580
587 if (!bt)
588 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
589#if 0
590 if (bt->is_dap4_only_type())
591 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
592#endif
593 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
594
595 BaseType *btp = bt->ptr_duplicate();
596 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
597 if (d_container) {
598 // Mem leak fix [mjohnson nov 2009]
599 // Structure::add_var() creates ANOTHER copy.
600 d_container->add_var(bt);
601 // So we need to delete btp or else it leaks
602 delete btp;
603 btp = 0;
604 }
605 else {
606 vars.push_back(btp);
607 }
608}
609
612void
614{
615 if (!bt)
616 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
617
618 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
619
620 if (d_container) {
621 d_container->add_var_nocopy(bt);
622 }
623 else {
624 vars.push_back(bt);
625 }
626}
627
628
635void
636DDS::del_var(const string &n)
637{
638 if( d_container )
639 {
640 d_container->del_var( n ) ;
641 return ;
642 }
643
644 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
645 if ((*i)->name() == n) {
646 BaseType *bt = *i ;
647 vars.erase(i) ;
648 delete bt ; bt = 0;
649 return;
650 }
651 }
652}
653
658void
659DDS::del_var(Vars_iter i)
660{
661 if (i != vars.end()) {
662 BaseType *bt = *i ;
663 vars.erase(i) ;
664 delete bt ; bt = 0;
665 }
666}
667
674void
675DDS::del_var(Vars_iter i1, Vars_iter i2)
676{
677 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
678 BaseType *bt = *i_tmp ;
679 delete bt ; bt = 0;
680 }
681 vars.erase(i1, i2) ;
682}
683
691BaseType *
692DDS::var(const string &n, BaseType::btp_stack &s)
693{
694 return var(n, &s);
695}
715BaseType *
716DDS::var(const string &n, BaseType::btp_stack *s)
717{
718 string name = www2id(n);
719 if( d_container )
720 return d_container->var( name, false, s ) ;
721
722 BaseType *v = exact_match(name, s);
723 if (v)
724 return v;
725
726 return leaf_match(name, s);
727}
728
729BaseType *
730DDS::leaf_match(const string &n, BaseType::btp_stack *s)
731{
732 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
733
734 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
735 BaseType *btp = *i;
736 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
737 // Look for the d_name in the dataset's top-level
738 if (btp->name() == n) {
739 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
740 return btp;
741 }
742
743 if (btp->is_constructor_type()) {
744 BaseType *found = btp->var(n, false, s);
745 if (found) {
746 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
747 return found;
748 }
749 }
750#if STRUCTURE_ARRAY_SYNTAX_OLD
751 if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
752 s->push(btp);
753 BaseType *found = btp->var()->var(n, false, s);
754 if (found) {
755 DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
756 return found;
757 }
758 }
759#endif
760 }
761
762 return 0; // It is not here.
763}
764
765BaseType *
766DDS::exact_match(const string &name, BaseType::btp_stack *s)
767{
768 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
769 BaseType *btp = *i;
770 DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
771 // Look for the d_name in the current ctor type or the top level
772 if (btp->name() == name) {
773 DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
774 return btp;
775 }
776 }
777
778 string::size_type dot_pos = name.find(".");
779 if (dot_pos != string::npos) {
780 string aggregate = name.substr(0, dot_pos);
781 string field = name.substr(dot_pos + 1);
782
783 BaseType *agg_ptr = var(aggregate, s);
784 if (agg_ptr) {
785 DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
786 return agg_ptr->var(field, true, s);
787 }
788 else
789 return 0; // qualified names must be *fully* qualified
790 }
791
792 return 0; // It is not here.
793}
794
795
798DDS::Vars_iter
800{
801 return vars.begin();
802}
803
804DDS::Vars_riter
806{
807 return vars.rbegin();
808}
809
810DDS::Vars_iter
812{
813 return vars.end() ;
814}
815
816DDS::Vars_riter
818{
819 return vars.rend() ;
820}
821
825DDS::Vars_iter
827{
828 return vars.begin() + i;
829}
830
834BaseType *
836{
837 return *(vars.begin() + i);
838}
839
844void
845DDS::insert_var(Vars_iter i, BaseType *ptr)
846{
847#if 0
848 if (ptr->is_dap4_only_type())
849 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
850#endif
851 vars.insert(i, ptr->ptr_duplicate());
852}
853
861void
863{
864#if 0
865 if (ptr->is_dap4_only_type())
866 throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
867#endif
868 vars.insert(i, ptr);
869}
870
872int
874{
875 return vars.size();
876}
877
878void
879DDS::timeout_on()
880{
881#if USE_LOCAL_TIMEOUT_SCHEME
882#ifndef WIN32
883 alarm(d_timeout);
884#endif
885#endif
886}
887
888void
889DDS::timeout_off()
890{
891#if USE_LOCAL_TIMEOUT_SCHEME
892#ifndef WIN32
893 // Old behavior commented out. I think it is an error to change the value
894 // of d_timeout. The way this will likely be used is to set the timeout
895 // value once and then 'turn on' or turn off' that timeout as the situation
896 // dictates. The initeded use for the DDS timeout is so that timeouts for
897 // data responses will include the CPU resources needed to build the response
898 // but not the time spent transmitting the response. This may change when
899 // more parallelism is added to the server... These methods are called from
900 // BESDapResponseBuilder in bes/dap. jhrg 12/22/15
901
902 // d_timeout = alarm(0);
903
904 alarm(0);
905#endif
906#endif
907}
908
909void
910DDS::set_timeout(int)
911{
912#if USE_LOCAL_TIMEOUT_SCHEME
913 // Has no effect under win32
914 d_timeout = t;
915#endif
916}
917
918int
919DDS::get_timeout()
920{
921#if USE_LOCAL_TIMEOUT_SCHEME
922 // Has to effect under win32
923 return d_timeout;
924#endif
925 return 0;
926}
927
929void
931{
932 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
933 if ((*i)->type() == dods_sequence_c)
934 dynamic_cast<Sequence&>(**i).set_leaf_sequence();
935 else if ((*i)->type() == dods_structure_c)
936 dynamic_cast<Structure&>(**i).set_leaf_sequence();
937 }
938}
939
941void
942DDS::parse(string fname)
943{
944 FILE *in = fopen(fname.c_str(), "r");
945
946 if (!in) {
947 throw Error(cannot_read_file, "Could not open: " + fname);
948 }
949
950 try {
951 parse(in);
952 fclose(in);
953 }
954 catch (Error &e) {
955 fclose(in);
956 throw ;
957 }
958}
959
960
962void
964{
965#ifdef WIN32
966 int new_fd = _dup(fd);
967#else
968 int new_fd = dup(fd);
969#endif
970
971 if (new_fd < 0)
972 throw InternalErr(__FILE__, __LINE__, "Could not access file.");
973 FILE *in = fdopen(new_fd, "r");
974
975 if (!in) {
976 throw InternalErr(__FILE__, __LINE__, "Could not access file.");
977 }
978
979 try {
980 parse(in);
981 fclose(in);
982 }
983 catch (Error &e) {
984 fclose(in);
985 throw ;
986 }
987}
988
995void
996DDS::parse(FILE *in)
997{
998 if (!in) {
999 throw InternalErr(__FILE__, __LINE__, "Null input stream.");
1000 }
1001
1002 void *buffer = dds_buffer(in);
1003 dds_switch_to_buffer(buffer);
1004
1005 parser_arg arg(this);
1006
1007 bool status = ddsparse(&arg) == 0;
1008
1009 dds_delete_buffer(buffer);
1010
1011 DBG2(cout << "Status from parser: " << status << endl);
1012
1013 // STATUS is the result of the parser function; if a recoverable error
1014 // was found it will be true but arg.status() will be false.
1015 if (!status || !arg.status()) {// Check parse result
1016 if (arg.error())
1017 throw *arg.error();
1018 }
1019}
1020
1022void
1023DDS::print(FILE *out)
1024{
1025 ostringstream oss;
1026 print(oss);
1027 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1028}
1029
1031void
1032DDS::print(ostream &out)
1033{
1034 out << "Dataset {\n" ;
1035
1036 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1037 (*i)->print_decl(out) ;
1038 }
1039
1040 out << "} " << id2www(d_name) << ";\n" ;
1041
1042 return ;
1043}
1044
1052bool
1054{
1055 for (AttrTable::Attr_iter i = a.attr_begin(), e = a.attr_end(); i != e; ++i) {
1056 if (a.get_attr_type(i) != Attr_container) {
1057 return true;
1058 }
1059 else if (has_dap2_attributes(*a.get_attr_table(i))) {
1060 return true;
1061 }
1062 }
1063
1064 return false;
1065
1066#if 0
1067 vector<AttrTable*> tables;
1068
1069 for (AttrTable::Attr_iter i = a.attr_begin(), e = a.attr_end(); i != e; ++i) {
1070 if (a.get_attr_type(i) != Attr_container)
1071 return true;
1072 else
1073 tables.push_back(a.get_attr_table(i));
1074 }
1075
1076 bool it_does = false;
1077 for (vector<AttrTable*>::iterartor i = tables.begin(), e = tables.end(); it_does || i != e; ++i) {
1078 it_does = has_dap2_attributes(**i);
1079 }
1080
1081 return it_does;
1082#endif
1083}
1084
1092bool
1094{
1096 return true;
1097 }
1098
1099 Constructor *cons = dynamic_cast<Constructor *>(btp);
1100 if (cons) {
1101 Grid* grid = dynamic_cast<Grid*>(btp);
1102 if(grid){
1103 return has_dap2_attributes(grid->get_array());
1104 }
1105 else {
1106 for (Constructor::Vars_iter i = cons->var_begin(), e = cons->var_end(); i != e; i++) {
1107 if (has_dap2_attributes(*i)) return true;
1108 }
1109 }
1110 }
1111 return false;
1112}
1113
1123static string four_spaces = " ";
1124void print_var_das(ostream &out, BaseType *bt, string indent = "") {
1125
1126 if (!has_dap2_attributes(bt))
1127 return;
1128
1129 AttrTable attr_table = bt->get_attr_table();
1130 out << indent << add_space_encoding(bt->name()) << " {" << endl;
1131
1132 Constructor *cnstrctr = dynamic_cast<Constructor *>(bt);
1133 if (cnstrctr) {
1134 Grid *grid = dynamic_cast<Grid *>(bt);
1135 if (grid) {
1136 Array *gridArray = grid->get_array();
1137 AttrTable arrayAT = gridArray->get_attr_table();
1138
1139 if (has_dap2_attributes(gridArray))
1140 gridArray->get_attr_table().print(out, indent + four_spaces);
1141#if 0
1142 // I dropped this because we don't want the MAP vectors showing up in the DAS
1143 // as children of a Grid (aka flatten the Grid bro) - ndp 5/25/18
1144 for (Grid::Map_iter mIter = grid->map_begin();
1145 mIter != grid->map_end(); ++mIter) {
1146 BaseType *currentMap = *mIter;
1147 if (has_dap2_attributes(currentMap))
1148 print_var_das(out, currentMap, indent + four_spaces);
1149 }
1150#endif
1151 }
1152 else {
1153 attr_table.print(out, indent + four_spaces);
1154 Constructor::Vars_iter i = cnstrctr->var_begin();
1155 Constructor::Vars_iter e = cnstrctr->var_end();
1156 for (; i != e; i++) {
1157 // Only call print_var_das() if there really are attributes.
1158 // This is made complicated because while there might be none
1159 // for a particular var (*i), that var might be a ctor and its
1160 // descendant might have an attribute. jhrg 3/18/18
1161 if (has_dap2_attributes(*i))
1162 print_var_das(out, *i, indent + four_spaces);
1163 }
1164 }
1165 }
1166 else {
1167 attr_table.print(out, indent + four_spaces);
1168 }
1169
1170 out << indent << "}" << endl;
1171}
1172
1181void
1182DDS::print_das(ostream &out)
1183{
1184#if 0
1185 string indent(" ");
1186 out << "Attributes {" << endl;
1187 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1188 if (has_dap2_attributes(*i))
1189 print_var_das(out, *i, four_spaces);
1190 }
1191 // Print the global attributes at the end.
1192 d_attr.print(out,indent);
1193 out << "}" << endl;
1194#endif
1195
1196 auto_ptr<DAS> das(get_das());
1197
1198 das->print(out);
1199}
1200
1210DAS *
1212{
1213 DAS *das = new DAS();
1214 get_das(das);
1215 return das;
1216}
1217
1223static string
1224get_unique_top_level_global_container_name(DAS *das)
1225{
1226 // It's virtually certain that the TOP_LEVE... name will be unique. If so,
1227 // return the name. The code tests for a table to see if the name _should not_ be used.
1228 AttrTable *table = das->get_table(TOP_LEVEL_ATTRS_CONTAINER_NAME);
1229 if (!table)
1230 return TOP_LEVEL_ATTRS_CONTAINER_NAME;
1231
1232 // ... but the default name might already be used
1233 unsigned int i = 0;
1234 string name;
1235 ostringstream oss;
1236 while (table) {
1237 oss.str(""); // reset to empty for the next suffix
1238 oss << "_" << ++i;
1239 if (!(i < UINT_MAX))
1240 throw InternalErr(__FILE__, __LINE__, "Cannot add top-level attributes to the DAS");
1241 name = TOP_LEVEL_ATTRS_CONTAINER_NAME + oss.str();
1242 table = das->get_table(name);
1243 }
1244
1245 return name;
1246}
1247
1256 Constructor *cons = dynamic_cast<Constructor *>(bt);
1257 if (cons) {
1258 Grid *grid = dynamic_cast<Grid *>(bt);
1259 if(grid){
1260 Array *gridArray = grid->get_array();
1261 AttrTable arrayAT = gridArray->get_attr_table();
1262
1263 for( AttrTable::Attr_iter atIter = arrayAT.attr_begin(); atIter!=arrayAT.attr_end(); ++atIter){
1264 AttrType type = arrayAT.get_attr_type(atIter);
1265 string childName = arrayAT.get_name(atIter);
1266 if (type == Attr_container){
1267 at->append_container( new AttrTable(*arrayAT.get_attr_table(atIter)), childName);
1268 }
1269 else {
1270 vector<string>* pAttrTokens = arrayAT.get_attr_vector(atIter);
1271 // append_attr makes a copy of the vector, so we don't have to do so here.
1272 at->append_attr(childName, AttrType_to_String(type), pAttrTokens);
1273 }
1274 }
1275
1276 }
1277 else {
1278 for (Constructor::Vars_iter i = cons->var_begin(), e = cons->var_end(); i != e; i++) {
1279 if (has_dap2_attributes(*i)) {
1280 AttrTable *childAttrT = new AttrTable((*i)->get_attr_table());
1281 fillConstructorAttrTable(childAttrT, *i);
1282 at->append_container(childAttrT,(*i)->name());
1283 }
1284 }
1285 }
1286 }
1287}
1288
1289void DDS::get_das(DAS *das)
1290{
1291 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1292 if (has_dap2_attributes(*i)) {
1293 AttrTable *childAttrT = new AttrTable((*i)->get_attr_table());
1294 fillConstructorAttrTable(childAttrT, *i);
1295 das->add_table((*i)->name(), childAttrT);
1296 }
1297 }
1298
1299 // Used in the rare case we have global attributes not in a table.
1300 auto_ptr<AttrTable> global(new AttrTable);
1301
1302 for (AttrTable::Attr_iter i = d_attr.attr_begin(); i != d_attr.attr_end(); ++i) {
1303 // It's possible, given the API and if the DDS was built from a DMR, that a
1304 // global attribute might not be a container; check for that.
1305 if (d_attr.get_attr_table(i)) {
1306 das->add_table(d_attr.get_name(i), new AttrTable(*(d_attr.get_attr_table(i))));
1307 }
1308 else {
1309 // This must be a top level attribute outside a container. jhrg 4/6/18
1310 global->append_attr(d_attr.get_name(i), d_attr.get_type(i), d_attr.get_attr_vector(i));
1311 }
1312 }
1313
1314 // if any attributes were added to 'global,' add it to the DAS and take control of the pointer.
1315 if (global->get_size() > 0) {
1316 das->add_table(get_unique_top_level_global_container_name(das), global.get()); // What if this name is not unique?
1317 global.release();
1318 }
1319}
1320
1331void
1333{
1334 ostringstream oss;
1335 print_constrained(oss);
1336 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1337}
1338
1349void
1351{
1352 out << "Dataset {\n" ;
1353
1354 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1355 // for each variable, indent with four spaces, print a trailing
1356 // semicolon, do not print debugging information, print only
1357 // variables in the current projection.
1358 (*i)->print_decl(out, " ", true, false, true) ;
1359 }
1360
1361 out << "} " << id2www(d_name) << ";\n" ;
1362
1363 return;
1364}
1365
1377void
1378DDS::print_xml(FILE *out, bool constrained, const string &blob)
1379{
1380 ostringstream oss;
1381 print_xml_writer(oss, constrained, blob);
1382 fwrite(oss.str().data(), 1, oss.str().length(), out);
1383}
1384
1396void
1397DDS::print_xml(ostream &out, bool constrained, const string &blob)
1398{
1399 print_xml_writer(out, constrained, blob);
1400}
1401
1402class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1403{
1404 XMLWriter &d_xml;
1405 bool d_constrained;
1406public:
1407 VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
1408 : d_xml(xml), d_constrained(constrained)
1409 {}
1410 void operator()(BaseType *bt)
1411 {
1412 bt->print_xml_writer(d_xml, d_constrained);
1413 }
1414};
1415
1432void
1433DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
1434{
1435 XMLWriter xml(" ");
1436
1437 // this is the old version of this method. It produced different output for
1438 // different version of DAP. We stopped using version numbers and use different
1439 // web api calls (DMR, DAP for DAP4 and DAS, DDS and DODS for DAP2) so the
1440 // dap version numbers are old and should not be used. There also seems to
1441 // be a bug where these version numbers change 'randomly' but which doesn't
1442 // show up in testing (or with valgrind or asan). jhrg 9/10/18
1443#if 0
1444 // Stamp and repeat for these sections; trying to economize is makes it
1445 // even more confusing
1446 if (get_dap_major() >= 4) {
1447 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1448 throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1449 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1450 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1451
1452 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0)
1453 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1454
1455 if (!get_request_xml_base().empty()) {
1456 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1457 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1458
1459 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1460 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1461 }
1462 if (!get_namespace().empty()) {
1463 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0)
1464 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1465 }
1466 }
1467 else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
1468 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1469 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1470 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1471 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1472 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1473 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1474
1475 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1476 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1477
1478 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1479 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1480
1481 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1482 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1483
1484 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1485 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1486 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1487 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1488
1489 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1490 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1491
1492 if (!get_request_xml_base().empty()) {
1493 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1494 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1495
1496 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1497 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1498 }
1499 }
1500 else { // dap2
1501 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1502 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1503 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1504 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1505 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1506 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1507
1508 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1509 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1510
1511 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1512 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1513 }
1514#endif
1515
1516#if DAP2_DDX
1517 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1518 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1519 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1520 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1521 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1522 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1523
1524 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1525 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1526
1527 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1528 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1529#elif DAP3_2_DDX
1530 // This is the 'DAP 3.2' DDX response - now the only response libdap will return.
1531 // jhrg 9/10/18
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 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*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1540 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1541
1542 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1543 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1544
1545 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1546 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1547
1548 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1549 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1550 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1551 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1552
1553 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1554 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1555
1556 if (!get_request_xml_base().empty()) {
1557 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1558 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1559
1560 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1561 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1562 }
1563#else
1564#error Must define DAP2_DDX or DAP3_2_DDX
1565#endif
1566
1567 // Print the global attributes
1568 d_attr.print_xml_writer(xml);
1569
1570 // Print each variable
1571 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1572
1573 // As above, this method now onl returns the DAP 3.2 version of the DDX response.
1574 // jhrg 9/10/28
1575#if 0
1576 // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1577 // the CID of the MIME part that holds the data. For DAP2 (which includes
1578 // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
1579 // given.
1580 if (get_dap_major() >= 4) {
1581 if (!blob.empty()) {
1582 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1583 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1584 string cid = "cid:" + blob;
1585 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1586 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1587 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1588 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1589 }
1590 }
1591 else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
1592 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1593 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1594 string cid = "cid:" + blob;
1595 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1596 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1597 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1598 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1599 }
1600 else { // dap2
1601 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1602 throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1603 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
1604 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1605 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1606 throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
1607 }
1608#endif
1609
1610#if DAP2_DDX
1611 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1612 throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1613 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 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 dataBLOB element");
1617#elif DAP3_2_DDX
1618 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1619 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1620 string cid = "cid:" + blob;
1621 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1622 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1623 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1624 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1625
1626 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1627 throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
1628#else
1629#error Must define DAP2_DDX or DAP3_2_DDX
1630#endif
1631
1632 out << xml.get_doc();// << ends;// << endl;
1633}
1634
1648void
1649DDS::print_dmr(ostream &out, bool constrained)
1650{
1651 if (get_dap_major() < 4)
1652 throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
1653
1654 XMLWriter xml(" ");
1655
1656 // DAP4 wraps a dataset in a top-level Group element.
1657 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1658 throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1659
1660 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
1661 (const xmlChar*) c_xml_namespace.c_str()) < 0)
1662 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1663
1664 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
1665 < 0)
1666 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1667
1668 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
1669 (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
1670 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1671
1672 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
1673 (const xmlChar*) get_namespace().c_str()) < 0)
1674 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1675
1676 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
1677 (const xmlChar*) get_dap_version().c_str()) < 0)
1678 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1679
1680 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
1681 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1682
1683 if (!get_request_xml_base().empty()) {
1684 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
1685 (const xmlChar*) get_request_xml_base().c_str()) < 0)
1686 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1687 }
1688
1689 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
1690 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1691
1692 // Print the global attributes
1693 d_attr.print_xml_writer(xml);
1694
1695 // Print each variable
1696 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1697
1698 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1699 throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
1700
1701 out << xml.get_doc();
1702}
1703
1704// Used by DDS::send() when returning data from a function call.
1719bool
1721{
1722 // The dataset must have a d_name
1723 if (d_name == "") {
1724 cerr << "A dataset must have a d_name" << endl;
1725 return false;
1726 }
1727
1728 string msg;
1729 if (!unique_names(vars, d_name, "Dataset", msg))
1730 return false;
1731
1732 if (all)
1733 for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1734 if (!(*i)->check_semantics(msg, true))
1735 return false;
1736
1737 return true;
1738}
1739
1763bool
1764DDS::mark(const string &n, bool state)
1765{
1766#if 0
1767 // TODO use auto_ptr
1768 BaseType::btp_stack *s = new BaseType::btp_stack;
1769#endif
1770
1771 auto_ptr<BaseType::btp_stack> s(new BaseType::btp_stack);
1772
1773 DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1774
1775 BaseType *variable = var(n, s.get());
1776 if (!variable) {
1777 throw Error(malformed_expr, "Could not find variable " + n);
1778#if 0
1779 DBG2(cerr << "Could not find variable " << n << endl);
1780#if 0
1781 delete s; s = 0;
1782#endif
1783 return false;
1784#endif
1785 }
1786 variable->set_send_p(state);
1787
1788 DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
1789 << " (a " << variable->type_name() << ")" << endl);
1790
1791 // Now check the btp_stack and run BaseType::set_send_p for every
1792 // BaseType pointer on the stack. Using BaseType::set_send_p() will
1793 // set the property for a Constructor but not its contained variables
1794 // which preserves the semantics of projecting just one field.
1795 while (!s->empty()) {
1796 s->top()->BaseType::set_send_p(state);
1797
1798 DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
1799 << " (a " << s->top()->type_name() << ")" << endl);
1800
1801 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1802 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1803 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1804
1805 s->pop();
1806 }
1807
1808#if 0
1809 delete s; s = 0;
1810#endif
1811
1812 return true;
1813}
1814
1820void
1821DDS::mark_all(bool state)
1822{
1823 for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1824 (*i)->set_send_p(state);
1825}
1826
1834void
1835DDS::dump(ostream &strm) const
1836{
1837 strm << DapIndent::LMarg << "DDS::dump - ("
1838 << (void *)this << ")" << endl ;
1839 DapIndent::Indent() ;
1840 strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
1841 strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1842 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1843 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1844 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1845
1846 strm << DapIndent::LMarg << "global attributes:" << endl ;
1847 DapIndent::Indent() ;
1848 d_attr.dump(strm) ;
1849 DapIndent::UnIndent() ;
1850
1851 if (vars.size()) {
1852 strm << DapIndent::LMarg << "vars:" << endl ;
1853 DapIndent::Indent() ;
1854 Vars_citer i = vars.begin() ;
1855 Vars_citer ie = vars.end() ;
1856 for (; i != ie; i++) {
1857 (*i)->dump(strm) ;
1858 }
1859 DapIndent::UnIndent() ;
1860 }
1861 else {
1862 strm << DapIndent::LMarg << "vars: none" << endl ;
1863 }
1864
1865 DapIndent::UnIndent() ;
1866}
1867
1868} // 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:363
void set_dap_major(int p)
Definition DDS.cc:404
void mark_all(bool state)
Definition DDS.cc:1821
void print_dmr(ostream &out, bool constrained)
Print the DAP4 DMR object using a DDS.
Definition DDS.cc:1649
Vars_riter var_rend()
Return a reverse iterator.
Definition DDS.cc:817
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition DDS.cc:613
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition DDS.cc:1720
string filename() const
Definition DDS.cc:387
virtual AttrTable & get_attr_table()
Definition DDS.cc:372
virtual void transfer_attributes(DAS *das)
Definition DDS.cc:286
void set_dap_minor(int p)
Definition DDS.cc:423
Vars_riter var_rbegin()
Return a reverse iterator.
Definition DDS.cc:805
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:873
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition DDS.cc:826
void print(FILE *out)
Print the entire DDS to the specified file.
Definition DDS.cc:1023
BaseType * get_var_index(int i)
Get a variable.
Definition DDS.cc:835
int get_request_size(bool constrained)
Get the estimated response size.
Definition DDS.cc:565
string get_dataset_name() const
Definition DDS.cc:356
void del_var(const string &n)
Removes a variable from the DDS.
Definition DDS.cc:636
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition DDS.cc:942
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition DDS.cc:692
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition DDS.cc:1378
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition DDS.cc:845
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition DDS.cc:1764
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:204
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition DDS.cc:930
DAS * get_das()
Get a DAS object.
Definition DDS.cc:1211
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition DDS.cc:1332
Vars_iter var_begin()
Return an iterator to the first variable.
Definition DDS.cc:799
string container_name()
Definition DDS.cc:511
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition DDS.cc:862
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:811
void set_dap_version(const string &version_string="2.0")
Definition DDS.cc:440
Structure * container()
Definition DDS.cc:547
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:586
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition DDS.cc:1433
void print_das(ostream &out)
write the DAS response given the attribute information in the DDS
Definition DDS.cc:1182
virtual void dump(ostream &strm) const
dumps information about this object
Definition DDS.cc:1835
libdap base object for common functionality of libdap objects
Definition DapObj.h:51
A class for error processing.
Definition Error.h:93
std::string get_error_message() const
Definition Error.cc:275
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:1053
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:1255
string id2www(string in, const string &allowable)
Definition escaping.cc:153
Pass parameters by reference to a parser.
Definition parser.h:69