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