libdap Updated for version 3.20.10
libdap4 is an implementation of OPeNDAP's DAP protocol.
DDS.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31//
32// jhrg 9/7/94
33
34#include "config.h"
35
36#include <cstdio>
37#include <cmath>
38#include <climits>
39//#include <cstdint>
40
41//#include <sys/types.h>
42
43#ifdef WIN32
44#include <io.h>
45#include <process.h>
46#include <fstream>
47#else
48#include <unistd.h> // for alarm and dup
49#include <sys/wait.h>
50#endif
51
52#include <iostream>
53#include <sstream>
54#include <algorithm>
55#include <functional>
56#include <memory>
57
58// #define DODS_DEBUG
59// #define DODS_DEBUG2
60
61#include "Byte.h"
62#include "Int16.h"
63#include "UInt16.h"
64#include "Int32.h"
65#include "UInt32.h"
66#include "Float32.h"
67#include "Float64.h"
68#include "Str.h"
69#include "Url.h"
70#include "Array.h"
71#include "Structure.h"
72#include "Sequence.h"
73#include "Grid.h"
74
75#include "DAS.h"
76#include "Clause.h"
77#include "Error.h"
78#include "InternalErr.h"
79#include "escaping.h"
80#include "parser.h"
81#include "debug.h"
82#include "util.h"
83#include "DapIndent.h"
84
90const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
91const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
92
93const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
94
95const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
96const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
97const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
98
99const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
100const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
101const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
102
103const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
104const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
105const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
106
110const string TOP_LEVEL_ATTRS_CONTAINER_NAME = "DAP4_GLOBAL";
111
112using namespace std;
113
114int ddsparse(libdap::parser_arg *arg);
115
116// Glue for the DDS parser defined in dds.lex
117void dds_switch_to_buffer(void *new_buffer);
118void dds_delete_buffer(void * buffer);
119void *dds_buffer(FILE *fp);
120
121namespace libdap {
122
123void
124DDS::duplicate(const DDS &dds)
125{
126 DBG(cerr << "Entering DDS::duplicate... " <<endl);
127
128 d_factory = dds.d_factory;
129
130 d_name = dds.d_name;
131 d_filename = dds.d_filename;
132 d_container_name = dds.d_container_name;
133 d_container = dds.d_container;
134
135 d_dap_major = dds.d_dap_major;
136 d_dap_minor = dds.d_dap_minor;
137
138 d_dap_version = dds.d_dap_version; // String version of the protocol
139 d_request_xml_base = dds.d_request_xml_base;
140 d_namespace = dds.d_namespace;
141
142 d_attr = dds.d_attr;
143
144 DDS &dds_tmp = const_cast<DDS &>(dds);
145
146 // copy the things pointed to by the list, not just the pointers
147 for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
148 add_var(*i); // add_var() dups the BaseType.
149 }
150
151 d_timeout = dds.d_timeout;
152
153 d_max_response_size_kb = dds.d_max_response_size_kb;
154}
155
168DDS::DDS(BaseTypeFactory *factory, const string &name)
169 : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
170 d_request_xml_base(""),
171 d_timeout(0), /*d_keywords(),*/ d_max_response_size_kb(0)
172{
173 DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
174
175 // This method sets a number of values, including those returned by
176 // get_protocol_major(), ..., get_namespace().
177 set_dap_version("2.0");
178}
179
195DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
196 : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
197 d_request_xml_base(""),
198 d_timeout(0), /*d_keywords(),*/ d_max_response_size_kb(0)
199{
200 DBG(cerr << "Building a DDS for version: " << version << endl);
201
202 // This method sets a number of values, including those returned by
203 // get_protocol_major(), ..., get_namespace().
204 set_dap_version(version);
205}
206
208DDS::DDS(const DDS &rhs) : DapObj()
209{
210 DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
211 duplicate(rhs);
212 DBG(cerr << " bye." << endl);
213}
214
215DDS::~DDS()
216{
217 // delete all the variables in this DDS
218 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
219 BaseType *btp = *i ;
220 delete btp ; btp = 0;
221 }
222}
223
224DDS &
225DDS::operator=(const DDS &rhs)
226{
227 if (this == &rhs)
228 return *this;
229 duplicate(rhs);
230 return *this;
231}
232
247{
248 // If there is a container set in the DDS then check the container from
249 // the DAS. If they are not the same container, then throw an exception
250 // (should be working on the same container). If the container does not
251 // exist in the DAS, then throw an exception
252 if (d_container && das->container_name() != d_container_name)
253 throw InternalErr(__FILE__, __LINE__,
254 "Error transferring attributes: working on a container in dds, but not das");
255
256 // Give each variable a chance to claim its attributes.
257 AttrTable *top = das->get_top_level_attributes();
258
259 for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
260 (*i)->transfer_attributes(top);
261 }
262
263 // Now we transfer all the attributes still marked as global to the
264 // global container in the DDS.
265 for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
266 if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
267 // copy the source container so that the DAS passed in can be
268 // deleted after calling this method.
269 AttrTable *at = new AttrTable(*(*i)->attributes);
270 d_attr.append_container(at, at->get_name());
271 }
272 }
273}
274
282
284string
286{
287 return d_name;
288}
289
291void
292DDS::set_dataset_name(const string &n)
293{
294 d_name = n;
295}
296
298
300AttrTable &
302{
303 return d_attr;
304}
305
315string
317{
318 return d_filename;
319}
320
322void
323DDS::filename(const string &fn)
324{
325 d_filename = fn;
326}
328
332void
334{
335 d_dap_major = p;
336
337 // This works because regardless of the order set_dap_major and set_dap_minor
338 // are called, once they both are called, the value in the string is
339 // correct. I protect against negative numbers because that would be
340 // nonsensical.
341 if (d_dap_minor >= 0) {
342 ostringstream oss;
343 oss << d_dap_major << "." << d_dap_minor;
344 d_dap_version = oss.str();
345 }
346}
347
351void
353{
354 d_dap_minor = p;
355
356 if (d_dap_major >= 0) {
357 ostringstream oss;
358 oss << d_dap_major << "." << d_dap_minor;
359 d_dap_version = oss.str();
360 }
361}
362
368void
369DDS::set_dap_version(const string &v /* = "2.0" */)
370{
371 istringstream iss(v);
372
373 int major = -1, minor = -1;
374 char dot;
375 if (!iss.eof() && !iss.fail())
376 iss >> major;
377 if (!iss.eof() && !iss.fail())
378 iss >> dot;
379 if (!iss.eof() && !iss.fail())
380 iss >> minor;
381
382 if (major == -1 || minor == -1 or dot != '.')
383 throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
384
385 d_dap_version = v;
386
387 d_dap_major = major;
388 d_dap_minor = minor;
389
390 // Now set the related XML constants. These might be overwritten if
391 // the DDS instance is being built from a document parse, but if it's
392 // being constructed by a server the code to generate the XML document
393 // needs these values to match the DAP version information.
394 switch (d_dap_major) {
395 case 2:
396 d_namespace = c_dap20_namespace;
397 break;
398 case 3:
399 d_namespace = c_dap32_namespace;
400 break;
401 case 4:
402 d_namespace = c_dap40_namespace;
403 break;
404 default:
405 throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
406 }
407}
408
416void
418{
419 int major = floor(d);
420 int minor = (d-major)*10;
421
422 DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
423
424 ostringstream oss;
425 oss << major << "." << minor;
426
427 set_dap_version(oss.str());
428}
429
439string
441{
442 return d_container_name;
443}
444
447void
448DDS::container_name(const string &cn)
449{
450 // we want to search the DDS for the top level structure with the given
451 // d_name. Set the container to null so that we don't search some previous
452 // container.
453 d_container = 0 ;
454 if( !cn.empty() )
455 {
456 d_container = dynamic_cast<Structure *>( var( cn ) ) ;
457 if( !d_container )
458 {
459 // create a structure for this container. Calling add_var
460 // while_container is null will add the new structure to DDS and
461 // not some sub structure. Adding the new structure makes a copy
462 // of it. So after adding it, go get it and set d_container.
463 Structure *s = new Structure( cn ) ;
464 add_var( s ) ;
465 delete s ;
466 s = 0 ;
467 d_container = dynamic_cast<Structure *>( var( cn ) ) ;
468 }
469 }
470 d_container_name = cn;
471
472}
473
475Structure *
477{
478 return d_container ;
479}
480
482
494//[[deprecated("Use DDS::get_request_size_kb()")]]
495int DDS::get_request_size(bool constrained)
496{
497 int w = 0;
498 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
499 if (constrained) {
500 if ((*i)->send_p())
501 w += (*i)->width(constrained);
502 }
503 else {
504 w += (*i)->width(constrained);
505 }
506 }
507 return w;
508}
509
522uint64_t DDS::get_request_size_kb(bool constrained)
523{
524 uint64_t req_size = 0;
525 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
526 if (constrained) {
527 if ((*i)->send_p())
528 req_size += (*i)->width(constrained);
529 }
530 else {
531 req_size += (*i)->width(constrained);
532 }
533 }
534 return req_size/1024;
535}
536
537
544 if (!bt)
545 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
546
547 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
548
549 BaseType *btp = bt->ptr_duplicate();
550 DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
551 if (d_container) {
552 // Mem leak fix [mjohnson nov 2009]
553 // Structure::add_var() creates ANOTHER copy.
554 d_container->add_var(bt);
555 // So we need to delete btp or else it leaks
556 delete btp;
557 btp = 0;
558 }
559 else {
560 vars.push_back(btp);
561 }
562}
563
566void
568{
569 if (!bt)
570 throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
571
572 DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
573
574 if (d_container) {
575 d_container->add_var_nocopy(bt);
576 }
577 else {
578 vars.push_back(bt);
579 }
580}
581
588void
589DDS::del_var(const string &n)
590{
591 if( d_container )
592 {
593 d_container->del_var( n ) ;
594 return ;
595 }
596
597 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
598 if ((*i)->name() == n) {
599 BaseType *bt = *i ;
600 vars.erase(i) ;
601 delete bt ; bt = 0;
602 return;
603 }
604 }
605}
606
611void
612DDS::del_var(Vars_iter i)
613{
614 if (i != vars.end()) {
615 BaseType *bt = *i ;
616 vars.erase(i) ;
617 delete bt ; bt = 0;
618 }
619}
620
627void
628DDS::del_var(Vars_iter i1, Vars_iter i2)
629{
630 for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
631 BaseType *bt = *i_tmp ;
632 delete bt ; bt = 0;
633 }
634 vars.erase(i1, i2) ;
635}
636
644BaseType *
645DDS::var(const string &n, BaseType::btp_stack &s)
646{
647 return var(n, &s);
648}
649
669BaseType *
670DDS::var(const string &n, BaseType::btp_stack *s)
671{
672 string name = www2id(n);
673 if( d_container )
674 return d_container->var( name, false, s ) ;
675
676 BaseType *v = exact_match(name, s);
677 if (v)
678 return v;
679
680 return leaf_match(name, s);
681}
682
683BaseType *
684DDS::leaf_match(const string &n, BaseType::btp_stack *s)
685{
686 DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
687
688 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
689 BaseType *btp = *i;
690 DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
691 // Look for the d_name in the dataset's top-level
692 if (btp->name() == n) {
693 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
694 return btp;
695 }
696
697 if (btp->is_constructor_type()) {
698 BaseType *found = btp->var(n, false, s);
699 if (found) {
700 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
701 return found;
702 }
703 }
704#if STRUCTURE_ARRAY_SYNTAX_OLD
705 if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
706 s->push(btp);
707 BaseType *found = btp->var()->var(n, false, s);
708 if (found) {
709 DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
710 return found;
711 }
712 }
713#endif
714 }
715
716 return 0; // It is not here.
717}
718
719BaseType *
720DDS::exact_match(const string &name, BaseType::btp_stack *s)
721{
722 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
723 BaseType *btp = *i;
724 DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
725 // Look for the d_name in the current ctor type or the top level
726 if (btp->name() == name) {
727 DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
728 return btp;
729 }
730 }
731
732 string::size_type dot_pos = name.find(".");
733 if (dot_pos != string::npos) {
734 string aggregate = name.substr(0, dot_pos);
735 string field = name.substr(dot_pos + 1);
736
737 BaseType *agg_ptr = var(aggregate, s);
738 if (agg_ptr) {
739 DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
740 return agg_ptr->var(field, true, s);
741 }
742 else
743 return 0; // qualified names must be *fully* qualified
744 }
745
746 return 0; // It is not here.
747}
748
753void
754DDS::insert_var(Vars_iter i, BaseType *ptr)
755{
756 vars.insert(i, ptr->ptr_duplicate());
757}
758
766void
768{
769 vars.insert(i, ptr);
770}
771
773int
775{
776 return vars.size();
777}
778
779void
780DDS::timeout_on()
781{
782#if USE_LOCAL_TIMEOUT_SCHEME
783#ifndef WIN32
784 alarm(d_timeout);
785#endif
786#endif
787}
788
789void
790DDS::timeout_off()
791{
792#if USE_LOCAL_TIMEOUT_SCHEME
793#ifndef WIN32
794 // Old behavior commented out. I think it is an error to change the value
795 // of d_timeout. The way this will likely be used is to set the timeout
796 // value once and then 'turn on' or turn off' that timeout as the situation
797 // dictates. The initeded use for the DDS timeout is so that timeouts for
798 // data responses will include the CPU resources needed to build the response
799 // but not the time spent transmitting the response. This may change when
800 // more parallelism is added to the server... These methods are called from
801 // BESDapResponseBuilder in bes/dap. jhrg 12/22/15
802
803 // d_timeout = alarm(0);
804
805 alarm(0);
806#endif
807#endif
808}
809
810void
811DDS::set_timeout(int)
812{
813#if USE_LOCAL_TIMEOUT_SCHEME
814 // Has no effect under win32
815 d_timeout = t;
816#endif
817}
818
819int
820DDS::get_timeout()
821{
822#if USE_LOCAL_TIMEOUT_SCHEME
823 // Has to effect under win32
824 return d_timeout;
825#endif
826 return 0;
827}
828
830void
832{
833 for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
834 if ((*i)->type() == dods_sequence_c)
835 dynamic_cast<Sequence&>(**i).set_leaf_sequence();
836 else if ((*i)->type() == dods_structure_c)
837 dynamic_cast<Structure&>(**i).set_leaf_sequence();
838 }
839}
840
842void
843DDS::parse(string fname)
844{
845 FILE *in = fopen(fname.c_str(), "r");
846
847 if (!in) {
848 throw Error(cannot_read_file, "Could not open: " + fname);
849 }
850
851 try {
852 parse(in);
853 fclose(in);
854 }
855 catch (Error &e) {
856 fclose(in);
857 throw ;
858 }
859}
860
861
863void
865{
866#ifdef WIN32
867 int new_fd = _dup(fd);
868#else
869 int new_fd = dup(fd);
870#endif
871
872 if (new_fd < 0)
873 throw InternalErr(__FILE__, __LINE__, "Could not access file.");
874 FILE *in = fdopen(new_fd, "r");
875
876 if (!in) {
877 throw InternalErr(__FILE__, __LINE__, "Could not access file.");
878 }
879
880 try {
881 parse(in);
882 fclose(in);
883 }
884 catch (Error &e) {
885 fclose(in);
886 throw ;
887 }
888}
889
896void
897DDS::parse(FILE *in)
898{
899 if (!in) {
900 throw InternalErr(__FILE__, __LINE__, "Null input stream.");
901 }
902
903 void *buffer = dds_buffer(in);
904 dds_switch_to_buffer(buffer);
905
906 parser_arg arg(this);
907
908 bool status = ddsparse(&arg) == 0;
909
910 dds_delete_buffer(buffer);
911
912 DBG2(cout << "Status from parser: " << status << endl);
913
914 // STATUS is the result of the parser function; if a recoverable error
915 // was found it will be true but arg.status() will be false.
916 if (!status || !arg.status()) {// Check parse result
917 if (arg.error())
918 throw *arg.error();
919 }
920}
921
923void
924DDS::print(FILE *out)
925{
926 ostringstream oss;
927 print(oss);
928 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
929}
930
932void
933DDS::print(ostream &out)
934{
935 out << "Dataset {\n" ;
936
937 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
938 (*i)->print_decl(out) ;
939 }
940
941 out << "} " << id2www(d_name) << ";\n" ;
942
943 return ;
944}
945
953bool
955{
956 for (AttrTable::Attr_iter i = a.attr_begin(), e = a.attr_end(); i != e; ++i) {
957 if (a.get_attr_type(i) != Attr_container) {
958 return true;
959 }
960 else if (has_dap2_attributes(*a.get_attr_table(i))) {
961 return true;
962 }
963 }
964
965 return false;
966}
967
975bool
977{
978 if (btp->get_attr_table().get_size() && has_dap2_attributes(btp->get_attr_table())) {
979 return true;
980 }
981
982 Constructor *cons = dynamic_cast<Constructor *>(btp);
983 if (cons) {
984 Grid* grid = dynamic_cast<Grid*>(btp);
985 if(grid){
986 return has_dap2_attributes(grid->get_array());
987 }
988 else {
989 for (Constructor::Vars_iter i = cons->var_begin(), e = cons->var_end(); i != e; i++) {
990 if (has_dap2_attributes(*i)) return true;
991 }
992 }
993 }
994 return false;
995}
996
1006static string four_spaces = " ";
1007void print_var_das(ostream &out, BaseType *bt, string indent = "") {
1008
1009 if (!has_dap2_attributes(bt))
1010 return;
1011
1012 AttrTable attr_table = bt->get_attr_table();
1013 out << indent << add_space_encoding(bt->name()) << " {" << endl;
1014
1015 Constructor *cnstrctr = dynamic_cast<Constructor *>(bt);
1016 if (cnstrctr) {
1017 Grid *grid = dynamic_cast<Grid *>(bt);
1018 if (grid) {
1019 Array *gridArray = grid->get_array();
1020 AttrTable arrayAT = gridArray->get_attr_table();
1021
1022 if (has_dap2_attributes(gridArray))
1023 gridArray->get_attr_table().print(out, indent + four_spaces);
1024#if 0
1025 // I dropped this because we don't want the MAP vectors showing up in the DAS
1026 // as children of a Grid (aka flatten the Grid bro) - ndp 5/25/18
1027 for (Grid::Map_iter mIter = grid->map_begin();
1028 mIter != grid->map_end(); ++mIter) {
1029 BaseType *currentMap = *mIter;
1030 if (has_dap2_attributes(currentMap))
1031 print_var_das(out, currentMap, indent + four_spaces);
1032 }
1033#endif
1034 }
1035 else {
1036 attr_table.print(out, indent + four_spaces);
1037 Constructor::Vars_iter i = cnstrctr->var_begin();
1038 Constructor::Vars_iter e = cnstrctr->var_end();
1039 for (; i != e; i++) {
1040 // Only call print_var_das() if there really are attributes.
1041 // This is made complicated because while there might be none
1042 // for a particular var (*i), that var might be a ctor and its
1043 // descendant might have an attribute. jhrg 3/18/18
1044 if (has_dap2_attributes(*i))
1045 print_var_das(out, *i, indent + four_spaces);
1046 }
1047 }
1048 }
1049 else {
1050 attr_table.print(out, indent + four_spaces);
1051 }
1052
1053 out << indent << "}" << endl;
1054}
1055
1064void
1065DDS::print_das(ostream &out)
1066{
1067 unique_ptr<DAS> das(get_das());
1068
1069 das->print(out);
1070}
1071
1081DAS *
1083{
1084 DAS *das = new DAS();
1085 get_das(das);
1086 return das;
1087}
1088
1094static string
1095get_unique_top_level_global_container_name(DAS *das)
1096{
1097 // It's virtually certain that the TOP_LEVE... name will be unique. If so,
1098 // return the name. The code tests for a table to see if the name _should not_ be used.
1099 AttrTable *table = das->get_table(TOP_LEVEL_ATTRS_CONTAINER_NAME);
1100 if (!table)
1101 return TOP_LEVEL_ATTRS_CONTAINER_NAME;
1102
1103 // ... but the default name might already be used
1104 unsigned int i = 0;
1105 string name;
1106 ostringstream oss;
1107 while (table) {
1108 oss.str(""); // reset to empty for the next suffix
1109 oss << "_" << ++i;
1110 if (!(i < UINT_MAX))
1111 throw InternalErr(__FILE__, __LINE__, "Cannot add top-level attributes to the DAS");
1112 name = TOP_LEVEL_ATTRS_CONTAINER_NAME + oss.str();
1113 table = das->get_table(name);
1114 }
1115
1116 return name;
1117}
1118
1127 Constructor *cons = dynamic_cast<Constructor *>(bt);
1128 if (cons) {
1129 Grid *grid = dynamic_cast<Grid *>(bt);
1130 if(grid){
1131 Array *gridArray = grid->get_array();
1132 AttrTable arrayAT = gridArray->get_attr_table();
1133
1134 for( AttrTable::Attr_iter atIter = arrayAT.attr_begin(); atIter!=arrayAT.attr_end(); ++atIter){
1135 AttrType type = arrayAT.get_attr_type(atIter);
1136 string childName = arrayAT.get_name(atIter);
1137 if (type == Attr_container){
1138 at->append_container( new AttrTable(*arrayAT.get_attr_table(atIter)), childName);
1139 }
1140 else {
1141 vector<string>* pAttrTokens = arrayAT.get_attr_vector(atIter);
1142 // append_attr makes a copy of the vector, so we don't have to do so here.
1143 at->append_attr(childName, AttrType_to_String(type), pAttrTokens);
1144 }
1145 }
1146
1147 }
1148 else {
1149 for (Constructor::Vars_iter i = cons->var_begin(), e = cons->var_end(); i != e; i++) {
1150 if (has_dap2_attributes(*i)) {
1151 AttrTable *childAttrT = new AttrTable((*i)->get_attr_table());
1152 fillConstructorAttrTable(childAttrT, *i);
1153 at->append_container(childAttrT,(*i)->name());
1154 }
1155 }
1156 }
1157 }
1158}
1159
1160void DDS::get_das(DAS *das)
1161{
1162 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1163 if (has_dap2_attributes(*i)) {
1164 AttrTable *childAttrT = new AttrTable((*i)->get_attr_table());
1165 fillConstructorAttrTable(childAttrT, *i);
1166 das->add_table((*i)->name(), childAttrT);
1167 }
1168 }
1169
1170 // Used in the rare case we have global attributes not in a table.
1171 unique_ptr<AttrTable> global(new AttrTable);
1172
1173 for (AttrTable::Attr_iter i = d_attr.attr_begin(); i != d_attr.attr_end(); ++i) {
1174 // It's possible, given the API and if the DDS was built from a DMR, that a
1175 // global attribute might not be a container; check for that.
1176 if (d_attr.get_attr_table(i)) {
1177 das->add_table(d_attr.get_name(i), new AttrTable(*(d_attr.get_attr_table(i))));
1178 }
1179 else {
1180 // This must be a top level attribute outside a container. jhrg 4/6/18
1181 global->append_attr(d_attr.get_name(i), d_attr.get_type(i), d_attr.get_attr_vector(i));
1182 }
1183 }
1184
1185 // if any attributes were added to 'global,' add it to the DAS and take control of the pointer.
1186 if (global->get_size() > 0) {
1187 das->add_table(get_unique_top_level_global_container_name(das), global.get()); // What if this name is not unique?
1188 global.release();
1189 }
1190}
1191
1202void
1204{
1205 ostringstream oss;
1206 print_constrained(oss);
1207 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1208}
1209
1220void
1222{
1223 out << "Dataset {\n" ;
1224
1225 for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1226 // for each variable, indent with four spaces, print a trailing
1227 // semicolon, do not print debugging information, print only
1228 // variables in the current projection.
1229 (*i)->print_decl(out, " ", true, false, true) ;
1230 }
1231
1232 out << "} " << id2www(d_name) << ";\n" ;
1233
1234 return;
1235}
1236
1248void
1249DDS::print_xml(FILE *out, bool constrained, const string &blob)
1250{
1251 ostringstream oss;
1252 print_xml_writer(oss, constrained, blob);
1253 fwrite(oss.str().data(), 1, oss.str().length(), out);
1254}
1255
1267void
1268DDS::print_xml(ostream &out, bool constrained, const string &blob)
1269{
1270 print_xml_writer(out, constrained, blob);
1271}
1272
1273class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1274{
1275 XMLWriter &d_xml;
1276 bool d_constrained;
1277public:
1278 VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
1279 : d_xml(xml), d_constrained(constrained)
1280 {}
1281 void operator()(BaseType *bt)
1282 {
1283 bt->print_xml_writer(d_xml, d_constrained);
1284 }
1285};
1286
1303void
1304DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
1305{
1306 XMLWriter xml(" ");
1307
1308 // This is the 'DAP 3.2' DDX response - now the only response libdap will return.
1309 // jhrg 9/10/18
1310 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1311 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1312 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1313 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1314 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1315 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1316
1317 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1318 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1319
1320 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1321 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1322
1323 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1324 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1325
1326 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1327 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1328 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1329 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1330
1331 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1332 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1333
1334 if (!get_request_xml_base().empty()) {
1335 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1336 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1337
1338 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1339 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1340 }
1341
1342 // Print the global attributes
1343 d_attr.print_xml_writer(xml);
1344
1345 // Print each variable
1346 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1347
1348 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1349 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1350 string cid = "cid:" + blob;
1351 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1352 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1353 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1354 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1355
1356 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1357 throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
1358
1359 out << xml.get_doc();// << ends;// << endl;
1360}
1361
1375void
1376DDS::print_dmr(ostream &out, bool constrained)
1377{
1378 if (get_dap_major() < 4)
1379 throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
1380
1381 XMLWriter xml(" ");
1382
1383 // DAP4 wraps a dataset in a top-level Group element.
1384 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1385 throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1386
1387 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
1388 (const xmlChar*) c_xml_namespace.c_str()) < 0)
1389 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1390
1391 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
1392 < 0)
1393 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1394
1395 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
1396 (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
1397 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1398
1399 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
1400 (const xmlChar*) get_namespace().c_str()) < 0)
1401 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1402
1403 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
1404 (const xmlChar*) get_dap_version().c_str()) < 0)
1405 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1406
1407 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
1408 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1409
1410 if (!get_request_xml_base().empty()) {
1411 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
1412 (const xmlChar*) get_request_xml_base().c_str()) < 0)
1413 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1414 }
1415
1416 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
1417 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1418
1419 // Print the global attributes
1420 d_attr.print_xml_writer(xml);
1421
1422 // Print each variable
1423 for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1424
1425 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1426 throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
1427
1428 out << xml.get_doc();
1429}
1430
1431// Used by DDS::send() when returning data from a function call.
1446bool
1448{
1449 // The dataset must have a d_name
1450 if (d_name == "") {
1451 cerr << "A dataset must have a d_name" << endl;
1452 return false;
1453 }
1454
1455 string msg;
1456 if (!unique_names(vars, d_name, "Dataset", msg))
1457 return false;
1458
1459 if (all)
1460 for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1461 if (!(*i)->check_semantics(msg, true))
1462 return false;
1463
1464 return true;
1465}
1466
1490bool
1491DDS::mark(const string &n, bool state)
1492{
1493 unique_ptr<BaseType::btp_stack> s(new BaseType::btp_stack);
1494
1495 DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1496
1497 BaseType *variable = var(n, s.get());
1498 if (!variable) {
1499 throw Error(malformed_expr, "Could not find variable " + n);
1500 }
1501
1502 variable->set_send_p(state);
1503
1504 DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
1505 << " (a " << variable->type_name() << ")" << endl);
1506
1507 // Now check the btp_stack and run BaseType::set_send_p for every
1508 // BaseType pointer on the stack. Using BaseType::set_send_p() will
1509 // set the property for a Constructor but not its contained variables
1510 // which preserves the semantics of projecting just one field.
1511 while (!s->empty()) {
1512 s->top()->BaseType::set_send_p(state);
1513
1514 DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
1515 << " (a " << s->top()->type_name() << ")" << endl);
1516
1517 string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1518 string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1519 DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1520
1521 s->pop();
1522 }
1523
1524 return true;
1525}
1526
1532void
1533DDS::mark_all(bool state)
1534{
1535 for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1536 (*i)->set_send_p(state);
1537}
1538
1546void
1547DDS::dump(ostream &strm) const
1548{
1549 strm << DapIndent::LMarg << "DDS::dump - ("
1550 << (void *)this << ")" << endl ;
1551 DapIndent::Indent() ;
1552 strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
1553 strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1554 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1555 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1556 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1557
1558 strm << DapIndent::LMarg << "global attributes:" << endl ;
1559 DapIndent::Indent() ;
1560 d_attr.dump(strm) ;
1561 DapIndent::UnIndent() ;
1562
1563 if (vars.size()) {
1564 strm << DapIndent::LMarg << "vars:" << endl ;
1565 DapIndent::Indent() ;
1566 Vars_citer i = vars.begin() ;
1567 Vars_citer ie = vars.end() ;
1568 for (; i != ie; i++) {
1569 (*i)->dump(strm) ;
1570 }
1571 DapIndent::UnIndent() ;
1572 }
1573 else {
1574 strm << DapIndent::LMarg << "vars: none" << endl ;
1575 }
1576
1577 DapIndent::UnIndent() ;
1578}
1579
1580} // 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 string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition AttrTable.cc:613
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:653
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
void print_xml_writer(XMLWriter &xml)
virtual void dump(ostream &strm) const
dumps information about this object
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual BaseType * ptr_duplicate()=0
BaseType * var(const string &name, bool exact_match=true, btp_stack *s=nullptr) override
btp_stack no longer needed; use back pointers (BaseType::get_parent())
void add_var(BaseType *bt, Part part=nil) override
void add_var_nocopy(BaseType *bt, Part part=nil) override
virtual void del_var(const string &name)
Remove an element from a Constructor.
Hold attribute data for a DAP2 dataset.
Definition DAS.h:122
void set_dataset_name(const string &n)
Definition DDS.cc:292
void set_dap_major(int p)
Definition DDS.cc:333
void mark_all(bool state)
Definition DDS.cc:1533
void print_dmr(ostream &out, bool constrained)
Print the DAP4 DMR object using a DDS.
Definition DDS.cc:1376
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition DDS.cc:567
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition DDS.cc:1447
string filename() const
Definition DDS.cc:316
virtual AttrTable & get_attr_table()
Definition DDS.cc:301
uint64_t get_request_size_kb(bool constrained)
Get the estimated response size in kilobytes.
Definition DDS.cc:522
virtual void transfer_attributes(DAS *das)
Definition DDS.cc:246
void set_dap_minor(int p)
Definition DDS.cc:352
string get_namespace() const
Get the namespace associated with the DDS - likely set only by DDX responses.
Definition DDS.h:279
int num_var()
Returns the number of variables in the DDS.
Definition DDS.cc:774
void print(FILE *out)
Print the entire DDS to the specified file.
Definition DDS.cc:924
int get_request_size(bool constrained)
Get the estimated response size in bytes.
Definition DDS.cc:495
string get_dataset_name() const
Definition DDS.cc:285
void del_var(const string &n)
Removes a variable from the DDS.
Definition DDS.cc:589
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition DDS.cc:843
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition DDS.cc:645
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition DDS.cc:1249
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition DDS.cc:754
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition DDS.cc:1491
DDS(BaseTypeFactory *factory, const string &name="")
Definition DDS.cc:168
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition DDS.cc:831
DAS * get_das()
Get a DAS object.
Definition DDS.cc:1082
Vars_iter var_begin()
Definition DDS.h:344
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition DDS.cc:1203
string container_name()
Definition DDS.cc:440
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition DDS.cc:767
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition DDS.h:273
Vars_iter var_end()
Return an iterator.
Definition DDS.h:349
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition DDS.h:257
void set_dap_version(const string &version_string="2.0")
Definition DDS.cc:369
Structure * container()
Definition DDS.cc:476
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:543
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition DDS.cc:1304
void print_das(ostream &out)
write the DAS response given the attribute information in the DDS
Definition DDS.cc:1065
virtual void dump(ostream &strm) const
dumps information about this object
Definition DDS.cc:1547
libdap base object for common functionality of libdap objects
Definition DapObj.h:51
A class for error processing.
Definition Error.h:94
Holds the Grid data type.
Definition Grid.h:123
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:1233
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:309
top level DAP object to house generic methods
bool has_dap2_attributes(AttrTable &a)
Definition DDS.cc:954
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:1126
string id2www(string in, const string &allowable)
Definition escaping.cc:153
Pass parameters by reference to a parser.
Definition parser.h:69