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