libdap  Updated for version 3.20.6
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 
96 const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
97 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
98 
99 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
100 
101 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
102 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
103 const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
104 
105 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
106 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
107 const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
108 
109 const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
110 const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
111 const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
112 
116 const string TOP_LEVEL_ATTRS_CONTAINER_NAME = "DAP4_GLOBAL";
117 
118 using namespace std;
119 
120 int ddsparse(libdap::parser_arg *arg);
121 
122 // Glue for the DDS parser defined in dds.lex
123 void dds_switch_to_buffer(void *new_buffer);
124 void dds_delete_buffer(void * buffer);
125 void *dds_buffer(FILE *fp);
126 
127 namespace libdap {
128 
129 void
130 DDS::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 
204 DDS::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 
231 DDS::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 
244 DDS::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 
251 DDS::~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 
260 DDS &
261 DDS::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.
297  AttrTable *top = das->get_top_level_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 
355 string
357 {
358  return d_name;
359 }
360 
362 void
363 DDS::set_dataset_name(const string &n)
364 {
365  d_name = n;
366 }
367 
369 
371 AttrTable &
373 {
374  return d_attr;
375 }
376 
386 string
388 {
389  return d_filename;
390 }
391 
393 void
394 DDS::filename(const string &fn)
395 {
396  d_filename = fn;
397 }
399 
403 void
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 
422 void
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 
439 void
440 DDS::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 
487 void
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 
510 string
512 {
513  return d_container_name;
514 }
515 
518 void
519 DDS::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 
546 Structure *
548 {
549  return d_container ;
550 }
551 
553 
564 int
565 DDS::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 
612 void
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 
635 void
636 DDS::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 
658 void
659 DDS::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 
674 void
675 DDS::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 
691 BaseType *
692 DDS::var(const string &n, BaseType::btp_stack &s)
693 {
694  return var(n, &s);
695 }
715 BaseType *
716 DDS::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 
729 BaseType *
730 DDS::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 
765 BaseType *
766 DDS::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 
798 DDS::Vars_iter
800 {
801  return vars.begin();
802 }
803 
804 DDS::Vars_riter
806 {
807  return vars.rbegin();
808 }
809 
810 DDS::Vars_iter
812 {
813  return vars.end() ;
814 }
815 
816 DDS::Vars_riter
818 {
819  return vars.rend() ;
820 }
821 
825 DDS::Vars_iter
827 {
828  return vars.begin() + i;
829 }
830 
834 BaseType *
836 {
837  return *(vars.begin() + i);
838 }
839 
844 void
845 DDS::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 
861 void
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 
872 int
874 {
875  return vars.size();
876 }
877 
878 void
879 DDS::timeout_on()
880 {
881 #if USE_LOCAL_TIMEOUT_SCHEME
882 #ifndef WIN32
883  alarm(d_timeout);
884 #endif
885 #endif
886 }
887 
888 void
889 DDS::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 
909 void
910 DDS::set_timeout(int)
911 {
912 #if USE_LOCAL_TIMEOUT_SCHEME
913  // Has no effect under win32
914  d_timeout = t;
915 #endif
916 }
917 
918 int
919 DDS::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 
929 void
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 
941 void
942 DDS::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 
962 void
963 DDS::parse(int fd)
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 
995 void
996 DDS::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 
1022 void
1023 DDS::print(FILE *out)
1024 {
1025  ostringstream oss;
1026  print(oss);
1027  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1028 }
1029 
1031 void
1032 DDS::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 
1052 bool
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 
1092 bool
1094 {
1095  if (btp->get_attr_table().get_size() && has_dap2_attributes(btp->get_attr_table())) {
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 
1123 static string four_spaces = " ";
1124 void 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 
1181 void
1182 DDS::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 
1210 DAS *
1212 {
1213  DAS *das = new DAS();
1214  get_das(das);
1215  return das;
1216 }
1217 
1223 static string
1224 get_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 
1289 void 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 
1331 void
1333 {
1334  ostringstream oss;
1335  print_constrained(oss);
1336  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1337 }
1338 
1349 void
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 
1377 void
1378 DDS::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 
1396 void
1397 DDS::print_xml(ostream &out, bool constrained, const string &blob)
1398 {
1399  print_xml_writer(out, constrained, blob);
1400 }
1401 
1402 class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1403 {
1404  XMLWriter &d_xml;
1405  bool d_constrained;
1406 public:
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 
1432 void
1433 DDS::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 
1648 void
1649 DDS::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.
1719 bool
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 
1763 bool
1764 DDS::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 
1820 void
1821 DDS::mark_all(bool state)
1822 {
1823  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1824  (*i)->set_send_p(state);
1825 }
1826 
1834 void
1835 DDS::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
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:320
AttrTable * get_table(AttrTable::Attr_iter &i)
Returns the referenced variable attribute table.
Definition: DAS.cc:179
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:1023
virtual Attr_iter attr_end()
Definition: AttrTable.cc:719
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition: DDS.cc:862
Contains the attributes for a dataset.
Definition: AttrTable.h:142
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition: DDS.cc:826
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:97
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition: DDS.cc:845
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:799
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: BaseType.cc:1134
string add_space_encoding(const string &s)
Definition: AttrTable.cc:78
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
virtual AttrTable * add_table(const string &name, AttrTable *at)
Adds a variable attribute table to the DAS or the current dataset container attribute table...
Definition: DAS.cc:209
DDS(BaseTypeFactory *factory, const string &name="")
Definition: DDS.cc:204
int get_request_size(bool constrained)
Get the estimated response size.
Definition: DDS.cc:565
STL namespace.
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition: DDS.cc:692
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:286
string filename() const
Definition: DDS.cc:387
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1378
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1243
Map_iter map_end()
Definition: Grid.cc:537
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition: DDS.cc:1433
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:613
Holds a structure (aggregate) type.
Definition: Structure.h:83
Vars_riter var_rend()
Return a reverse iterator.
Definition: DDS.cc:817
string get_dataset_name() const
Definition: DDS.cc:356
int num_var()
Returns the number of variables in the DDS.
Definition: DDS.cc:873
DAS * get_das()
Get a DAS object.
Definition: DDS.cc:1211
top level DAP object to house generic methods
Definition: AISConnect.cc:30
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition: DDS.cc:1764
A class for software fault reporting.
Definition: InternalErr.h:64
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition: DDS.cc:942
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:525
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 void set_send_p(bool state)
Definition: BaseType.cc:568
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
void mark_all(bool state)
Definition: DDS.cc:1821
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
void print_das(ostream &out)
write the DAS response given the attribute information in the DDS
Definition: DDS.cc:1182
Holds the Grid data type.
Definition: Grid.h:122
void print_dmr(ostream &out, bool constrained)
Print the DAP4 DMR object using a DDS.
Definition: DDS.cc:1649
virtual AttrTable & get_attr_table()
Definition: DDS.cc:372
BaseType * get_var_index(int i)
Get a variable.
Definition: DDS.cc:835
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition: DDS.cc:1720
Structure * container()
Definition: DDS.cc:547
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required...
Definition: Grid.cc:518
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition: DDS.h:266
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition: DDS.h:286
string container_name()
Definition: DDS.cc:511
std::string get_error_message() const
Definition: Error.cc:278
virtual AttrTable * get_top_level_attributes()
Returns the top most set of attributes.
Definition: DAS.h:166
virtual void dump(ostream &strm) const
dumps information about this object
Definition: DDS.cc:1835
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:711
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
virtual BaseType * ptr_duplicate()=0
string get_namespace() const
Get the namespace associated with the DDS - likely set only by DDX responses.
Definition: DDS.h:292
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
bool has_dap2_attributes(AttrTable &a)
Definition: DDS.cc:1053
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:811
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:930
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:582
void set_dap_minor(int p)
Definition: DDS.cc:423
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
void set_dataset_name(const string &n)
Definition: DDS.cc:363
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
libdap base object for common functionality of libdap objects
Definition: DapObj.h:50
Pass parameters by reference to a parser.
Definition: parser.h:68
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:621
void del_var(const string &n)
Removes a variable from the DDS.
Definition: DDS.cc:636
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:379
Vars_iter var_begin()
Definition: Constructor.cc:356
Vars_riter var_rbegin()
Return a reverse iterator.
Definition: DDS.cc:805
Vars_iter var_end()
Definition: Constructor.cc:364
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:653
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
A class for error processing.
Definition: Error.h:92
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition: AttrTable.cc:231
void fillConstructorAttrTable(AttrTable *at, BaseType *bt)
Recursive helper function for Building DAS entries for Constructor types.
Definition: DDS.cc:1255
int get_dap_minor() const
Get the DAP minor version as sent by the client.
Definition: DDS.h:268
void set_dap_major(int p)
Definition: DDS.cc:404
A multidimensional array of identical data types.
Definition: Array.h:112
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:1332
AttrType
Definition: AttrTable.h:81
void set_dap_version(const string &version_string="2.0")
Definition: DDS.cc:440
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
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