libdap++  Updated for version 3.8.2
DDS.cc
Go to the documentation of this file.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 static char rcsid[] not_used =
37  {"$Id: DDS.cc 25066 2011-11-30 18:39:37Z jimg $"
38  };
39 
40 #include <cstdio>
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 
57 //#define DODS_DEBUG
58 //#define DODS_DEBUG2
59 
60 #include "GNURegex.h"
61 
62 #include "DAS.h"
63 #include "Clause.h"
64 #include "Error.h"
65 #include "InternalErr.h"
66 #include "Keywords2.h"
67 
68 #include "parser.h"
69 #include "debug.h"
70 #include "util.h"
71 
72 #include "Byte.h"
73 #include "Int16.h"
74 #include "UInt16.h"
75 #include "Int32.h"
76 #include "UInt32.h"
77 #include "Float32.h"
78 #include "Float64.h"
79 #include "Str.h"
80 #include "Url.h"
81 #include "Array.h"
82 #include "Structure.h"
83 #include "Sequence.h"
84 #include "Grid.h"
85 
86 #include "escaping.h"
87 
88 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
89 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
90 
91 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
92 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
93 
96 
97 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
98 
99 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
100 
101 using namespace std;
102 
103 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
104 int ddsparse(void *arg);
105 
106 // Glue for the DDS parser defined in dds.lex
107 void dds_switch_to_buffer(void *new_buffer);
108 void dds_delete_buffer(void * buffer);
109 void *dds_buffer(FILE *fp);
110 
111 namespace libdap {
112 
113 void
114 DDS::duplicate(const DDS &dds)
115 {
116  DBG(cerr << "Entering DDS::duplicate... " <<endl);
117  name = dds.name;
118  d_filename = dds.d_filename;
119  d_container_name = dds.d_container_name;
120  d_timeout = dds.d_timeout;
121  d_attr = dds.d_attr;
122 
123  d_factory = dds.d_factory;
124  d_container = dds.d_container;
125  d_dap_major = dds.d_dap_major;
126  d_dap_minor = dds.d_dap_minor;
127 
128  d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
129 
130  DDS &dds_tmp = const_cast<DDS &>(dds);
131 
132  // copy the things pointed to by the list, not just the pointers
133  for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
134  add_var(*i); // add_var() dups the BaseType.
135  }
136 }
137 
148 DDS::DDS(BaseTypeFactory *factory, const string &n)
149  : d_factory(factory), name(n), d_container(0),
150  d_dap_major(2), d_dap_minor(0),
151  d_request_xml_base(""), d_timeout(0), d_keywords(),
152  d_max_response_size(0)
153 {
154  DBG(cerr << "Building a DDS with client major/minor: "
155  << d_dap_major << "." << d_dap_minor << endl);
156 }
157 
159 DDS::DDS(const DDS &rhs) : DapObj()
160 {
161  DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
162  duplicate(rhs);
163  DBG(cerr << " bye." << endl);
164 }
165 
167 {
168  // delete all the variables in this DDS
169  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
170  BaseType *btp = *i ;
171  delete btp ; btp = 0;
172  }
173 }
174 
175 DDS &
176 DDS::operator=(const DDS &rhs)
177 {
178  DBG(cerr << "Entering DDS::operator= ..." << endl);
179  if (this == &rhs)
180  return *this;
181 
182  duplicate(rhs);
183 
184  DBG(cerr << " bye." << endl);
185  return *this;
186 }
187 
202  // If there is a container set in the DDS then get the container from
203  // the DAS. If they are not the same container, then throw an exception
204  // (should be working on the same container). If the container does not
205  // exist in the DAS, then throw an exception
206  if (d_container) {
207  if (das->container_name() != d_container_name)
208  throw InternalErr(__FILE__, __LINE__,
209  "Error transferring attributes: working on a container in dds, but not das");
210  }
211 
212  // Give each variable a chance to claim its attributes.
213  AttrTable *top_level = das->get_top_level_attributes();
214 
215  Vars_iter var = var_begin();
216  while (var != var_end()) {
217  try {
218  DBG(cerr << "Processing the attributes for: " << (*var)->name() << " a " << (*var)->type_name() << endl);
219  (*var)->transfer_attributes(top_level);
220  var++;
221  } catch (Error &e) {
222  DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
223  var++;
224  throw e;
225  }
226  }
227 
228  // Now we transfer all of the attributes still marked as global to the
229  // global container in the DDS.
230 
231  AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
232  while (at_cont_p != top_level->attr_end()) {
233  // In truth, all of the top level attributes should be containers, but
234  // this test handles the abnormal case where somehow someone makes a
235  // top level attribute that is not a container by silently dropping it.
236  if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
237  DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl);
238  // copy the source container so that the DAS passed in can be
239  // deleted after calling this method.
240  AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
241  d_attr.append_container(at, at->get_name());
242  }
243 
244  at_cont_p++;
245  }
246 }
247 
255 
257 string
259 {
260  return name;
261 }
262 
264 void
265 DDS::set_dataset_name(const string &n)
266 {
267  name = n;
268 }
269 
271 
273 AttrTable &
275 {
276  return d_attr;
277 }
278 
288 string
290 {
291  return d_filename;
292 }
293 
295 void
296 DDS::filename(const string &fn)
297 {
298  d_filename = fn;
299 }
301 
302 void
304 {
305  d_dap_major = p;
306 
307  // This works because regardless of the order set_dap_major and set_dap_minor
308  // are called, once they both are called, the value in the string is
309  // correct. I protect against negative numbers because that would be
310  // nonsensical.
311  if (d_dap_minor >= 0) {
312  ostringstream oss;
313  oss << d_dap_major << "." << d_dap_minor;
314  d_dap_version = oss.str();
315  }
316 }
317 
318 void
320 {
321  d_dap_minor = p;
322 
323  if (d_dap_major >= 0) {
324  ostringstream oss;
325  oss << d_dap_major << "." << d_dap_minor;
326  d_dap_version = oss.str();
327  }
328 }
329 
336 void
337 DDS::set_dap_version(const string &version_string)
338 {
339  istringstream iss(version_string);
340 
341  int major = -1, minor = -1;
342  char dot;
343  if (!iss.eof() && !iss.fail())
344  iss >> major;
345  if (!iss.eof() && !iss.fail())
346  iss >> dot;
347  if (!iss.eof() && !iss.fail())
348  iss >> minor;
349 
350  DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
351 #if 0
352  if (major == -1 || minor == -1)
353  throw Error("Could not parse the client dap (XDAP-Accept header) value");
354 #endif
355 
356  d_dap_version = version_string;
357 
358  set_dap_major(major == -1 ? 2 : major);
359  set_dap_minor(minor == -1 ? 0 : minor);
360 }
361 
369 void
371 {
372  int major = d;
373  int minor = (d-major)*10;
374 
375  DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
376 
377  ostringstream oss;
378  oss << major << "." << minor;
379  d_dap_version = oss.str();
380 
381  set_dap_major(major);
382  set_dap_minor(minor);
383 }
384 
394 string
396 {
397  return d_container_name;
398 }
399 
402 void
403 DDS::container_name(const string &cn)
404 {
405  // we want to search the DDS for the top level structure with the given
406  // name. Set the container to null so that we don't search some previous
407  // container.
408  d_container = 0 ;
409  if( !cn.empty() )
410  {
411  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
412  if( !d_container )
413  {
414  // create a structure for this container. Calling add_var
415  // while_container is null will add the new structure to DDS and
416  // not some sub structure. Adding the new structure makes a copy
417  // of it. So after adding it, go get it and set d_container.
418  Structure *s = new Structure( cn ) ;
419  add_var( s ) ;
420  delete s ;
421  s = 0 ;
422  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
423  }
424  }
425  d_container_name = cn;
426 
427 }
428 
430 Structure *
432 {
433  return d_container ;
434 }
435 
437 
448 int
449 DDS::get_request_size(bool constrained)
450 {
451  int w = 0;
452  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
453  if (constrained) {
454  if ((*i)->send_p())
455  w += (*i)->width(constrained);
456  }
457  else {
458  w += (*i)->width(constrained);
459  }
460  }
461 
462  return w;
463 }
464 
471  if (!bt)
472  throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
473 
474  DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
475 
476  BaseType *btp = bt->ptr_duplicate();
477  DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
478  if (d_container) {
479  // Mem leak fix [mjohnson nov 2009]
480  // Structure::add_var() creates ANOTHER copy.
481  d_container->add_var(bt);
482  // So we need to delete btp or else it leaks
483  delete btp;
484  btp = 0;
485  }
486  else {
487  vars.push_back(btp);
488  }
489 }
490 
494  if (!bt)
495  throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
496 
497  DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
498 
499  BaseType *btp = bt->ptr_duplicate();
500  DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
501  if (d_container) {
502  // Mem leak fix [mjohnson nov 2009]
503  // Structure::add_var() creates ANOTHER copy.
504  d_container->add_var(bt);
505  // So we need to delete btp or else it leaks
506  delete btp;
507  btp = 0;
508  }
509  else {
510  vars.push_back(btp);
511  }
512 }
513 
514 
521 void
522 DDS::del_var(const string &n)
523 {
524  if( d_container )
525  {
526  d_container->del_var( n ) ;
527  return ;
528  }
529 
530  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
531  if ((*i)->name() == n) {
532  BaseType *bt = *i ;
533  vars.erase(i) ;
534  delete bt ; bt = 0;
535  return;
536  }
537  }
538 }
539 
544 void
546 {
547  if (i != vars.end()) {
548  BaseType *bt = *i ;
549  vars.erase(i) ;
550  delete bt ; bt = 0;
551  }
552 }
553 
560 void
562 {
563  for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
564  BaseType *bt = *i_tmp ;
565  delete bt ; bt = 0;
566  }
567  vars.erase(i1, i2) ;
568 }
569 
577 BaseType *
578 DDS::var(const string &n, BaseType::btp_stack &s)
579 {
580  return var(n, &s);
581 }
601 BaseType *
602 DDS::var(const string &n, BaseType::btp_stack *s)
603 {
604  string name = www2id(n);
605  if( d_container )
606  return d_container->var( name, false, s ) ;
607 
608  BaseType *v = exact_match(name, s);
609  if (v)
610  return v;
611 
612  return leaf_match(name, s);
613 }
614 
615 BaseType *
617 {
618  DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
619 
620  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
621  BaseType *btp = *i;
622  DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
623  // Look for the name in the dataset's top-level
624  if (btp->name() == n) {
625  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
626  return btp;
627  }
628 
629  if (btp->is_constructor_type()) {
630  BaseType *found = btp->var(n, false, s);
631  if (found) {
632  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
633  return found;
634  }
635  }
636 #if STRUCTURE_ARRAY_SYNTAX_OLD
637  if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
638  s->push(btp);
639  BaseType *found = btp->var()->var(n, false, s);
640  if (found) {
641  DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
642  return found;
643  }
644  }
645 #endif
646  }
647 
648  return 0; // It is not here.
649 }
650 
651 BaseType *
652 DDS::exact_match(const string &name, BaseType::btp_stack *s)
653 {
654  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
655  BaseType *btp = *i;
656  DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
657  // Look for the name in the current ctor type or the top level
658  if (btp->name() == name) {
659  DBG2(cerr << "Found " << name << " in: " << btp << endl);
660  return btp;
661  }
662  }
663 
664  string::size_type dot_pos = name.find(".");
665  if (dot_pos != string::npos) {
666  string aggregate = name.substr(0, dot_pos);
667  string field = name.substr(dot_pos + 1);
668 
669  BaseType *agg_ptr = var(aggregate, s);
670  if (agg_ptr) {
671  DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
672  return agg_ptr->var(field, true, s);
673  }
674  else
675  return 0; // qualified names must be *fully* qualified
676  }
677 
678  return 0; // It is not here.
679 }
680 
681 
686 {
687  return vars.begin();
688 }
689 
692 {
693  return vars.rbegin();
694 }
695 
698 {
699  return vars.end() ;
700 }
701 
704 {
705  return vars.rend() ;
706 }
707 
713 {
714  return vars.begin() + i;
715 }
716 
720 BaseType *
722 {
723  return *(vars.begin() + i);
724 }
725 
730 void
732 {
733  vars.insert(i, ptr->ptr_duplicate());
734 }
735 
743 void
745 {
746  vars.insert(i, ptr);
747 }
748 
750 int
752 {
753  return vars.size();
754 }
755 
756 void
758 {
759 #ifndef WIN32
760  alarm(d_timeout);
761 #endif
762 }
763 
764 void
766 {
767 #ifndef WIN32
768  d_timeout = alarm(0);
769 #endif
770 }
771 
772 void
774 {
775  // Has no effect under win32
776  d_timeout = t;
777 }
778 
779 int
781 {
782  // Has to effect under win32
783  return d_timeout;
784 }
785 
787 void
789 {
790  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
791  if ((*i)->type() == dods_sequence_c)
792  dynamic_cast<Sequence&>(**i).set_leaf_sequence();
793  else if ((*i)->type() == dods_structure_c)
794  dynamic_cast<Structure&>(**i).set_leaf_sequence();
795  }
796 }
797 
799 void
800 DDS::parse(string fname)
801 {
802  FILE *in = fopen(fname.c_str(), "r");
803 
804  if (!in) {
805  throw Error(cannot_read_file, "Could not open: " + fname);
806  }
807 
808  try {
809  parse(in);
810  fclose(in);
811  }
812  catch (Error &e) {
813  fclose(in);
814  throw ;
815  }
816 }
817 
818 
820 void
821 DDS::parse(int fd)
822 {
823 #ifdef WIN32
824  FILE *in = fdopen(_dup(fd), "r");
825 #else
826  FILE *in = fdopen(dup(fd), "r");
827 #endif
828 
829  if (!in) {
830  throw InternalErr(__FILE__, __LINE__, "Could not access file.");
831  }
832 
833  try {
834  parse(in);
835  fclose(in);
836  }
837  catch (Error &e) {
838  fclose(in);
839  throw ;
840  }
841 }
842 
849 void
850 DDS::parse(FILE *in)
851 {
852  if (!in) {
853  throw InternalErr(__FILE__, __LINE__, "Null input stream.");
854  }
855 
856  void *buffer = dds_buffer(in);
857  dds_switch_to_buffer(buffer);
858 
859  parser_arg arg(this);
860 
861  bool status = ddsparse((void *) & arg) == 0;
862 
863  dds_delete_buffer(buffer);
864 
865  DBG2(cout << "Status from parser: " << status << endl);
866 
867  // STATUS is the result of the parser function; if a recoverable error
868  // was found it will be true but arg.status() will be false.
869  if (!status || !arg.status()) {// Check parse result
870  if (arg.error())
871  throw *arg.error();
872  }
873 }
874 
875 #if FILE_METHODS
876 
877 void
878 DDS::print(FILE *out)
879 {
880 #if 0
881  ostringstream oss;
882  print(oss);
883 
884  fwrite(oss.str().c_str(), oss.str().length(), 1, out);
885 #else
886  fprintf(out, "Dataset {\n") ;
887 
888  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
889  (*i)->print_decl(out) ;
890  }
891 
892  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
893 
894  return ;
895 #endif
896 }
897 #endif
898 
900 void
901 DDS::print(ostream &out)
902 {
903  out << "Dataset {\n" ;
904 
905  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
906  (*i)->print_decl(out) ;
907  }
908 
909  out << "} " << id2www(name) << ";\n" ;
910 
911  return ;
912 }
913 
914 #if FILE_METHODS
915 
925 void
927 {
928  fprintf(out, "Dataset {\n") ;
929 
930  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
931  // for each variable, indent with four spaces, print a trailing
932  // semicolon, do not print debugging information, print only
933  // variables in the current projection.
934  (*i)->print_decl(out, " ", true, false, true) ;
935  }
936 
937  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
938 
939  return;
940 }
941 #endif
942 
953 void
955 {
956  out << "Dataset {\n" ;
957 
958  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
959  // for each variable, indent with four spaces, print a trailing
960  // semicolon, do not print debugging information, print only
961  // variables in the current projection.
962  (*i)->print_decl(out, " ", true, false, true) ;
963  }
964 
965  out << "} " << id2www(name) << ";\n" ;
966 
967  return;
968 }
969 
970 #if FILE_METHODS
971 class VariablePrintXML : public unary_function<BaseType *, void>
972 {
973  FILE *d_out;
974  bool d_constrained;
975 public:
976  VariablePrintXML(FILE *out, bool constrained)
977  : d_out(out), d_constrained(constrained)
978  {}
979  void operator()(BaseType *bt)
980  {
981  bt->print_xml(d_out, " ", d_constrained);
982  }
983 };
984 
996 void
997 DDS::print_xml(FILE *out, bool constrained, const string &blob)
998 {
999  ostringstream oss;
1000  print_xml_writer(oss, constrained, blob);
1001 
1002  string doc = oss.str();
1003  fwrite(doc.data(), 1, doc.length(), out);
1004 
1005 #if 0
1006  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1007 
1008  fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
1009 
1010  fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1011 
1012  fprintf(out,"method=\"FILE*\"\n");
1013  fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
1014  fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
1015 
1016  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1017  // this at some point... jhrg
1018  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1019  fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
1020 
1021  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
1023  }
1024  else {
1025  fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
1026  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
1028  }
1029 
1030 
1031  d_attr.print_xml(out, " ", constrained);
1032 
1033  fprintf(out, "\n");
1034 
1035  for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
1036 
1037  fprintf(out, "\n");
1038 
1039  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1040  // the same. jhrg
1041  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1042  fprintf(out, " <dataBLOB href=\"\"/>\n");
1043  }
1044  else if (!blob.empty()
1045  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1046  || get_dap_major() >= 4) {
1047  fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str());
1048  }
1049 
1050 
1051  fprintf(out, "</Dataset>\n");
1052 #endif
1053 }
1054 #endif
1055 
1056 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
1057 {
1058  ostream &d_out;
1059  bool d_constrained;
1060 public:
1061  VariablePrintXMLStrm(ostream &out, bool constrained)
1062  : d_out(out), d_constrained(constrained)
1063  {}
1064  void operator()(BaseType *bt)
1065  {
1066  bt->print_xml(d_out, " ", d_constrained);
1067  }
1068 };
1069 
1081 void
1082 DDS::print_xml(ostream &out, bool constrained, const string &blob)
1083 {
1084  print_xml_writer(out, constrained, blob);
1085 
1086 #if 0
1087  out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
1088 
1089  out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
1090 
1091  out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
1092 
1093  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1094  // this at some point... jhrg
1095  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1096  out << "xsi:schemaLocation=\"" << c_dap32_namespace
1097  << " " << c_default_dap32_schema_location << "\"\n" ;
1098 
1099  out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
1100  out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
1101 
1102  out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
1103  out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
1104 
1105  out << "dapVersion=\"" << get_dap_major() << "."
1106  << get_dap_minor() << "\"";
1107 
1108  if (!get_request_xml_base().empty()) {
1109  out << "\n";
1110  out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
1111  out << "xml:base=\"" << get_request_xml_base() << "\"";
1112  }
1113 
1114  // Close the Dataset element
1115  out << ">\n";
1116  }
1117  else {
1118  out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
1119  out << "xsi:schemaLocation=\"" << c_dap20_namespace
1120  << " " << c_default_dap20_schema_location << "\">\n\n" ;
1121  }
1122 
1123  d_attr.print_xml(out, " ", constrained);
1124 
1125  out << "\n" ;
1126 
1127  for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
1128 
1129  out << "\n" ;
1130 
1131  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1132  // the same.
1133  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1134  // actually the CID of the MIME part that holds the data.
1135  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1136  out << " <dataBLOB href=\"\"/>\n" ;
1137  }
1138  else if (!blob.empty()
1139  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1140  || get_dap_major() >= 4) {
1141  out << " <blob href=\"cid:" << blob << "\"/>\n";
1142  }
1143 
1144  out << "</Dataset>\n" ;
1145 #endif
1146 }
1147 
1148 class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1149 {
1150  XMLWriter &d_xml;
1151  bool d_constrained;
1152 public:
1153  VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
1154  : d_xml(xml), d_constrained(constrained)
1155  {}
1156  void operator()(BaseType *bt)
1157  {
1158  bt->print_xml_writer(d_xml, d_constrained);
1159  }
1160 };
1161 
1162 
1163 void
1164 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
1165 {
1166  XMLWriter xml(" ");
1167 
1168  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1169  throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1170  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name.c_str()) < 0)
1171  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1172  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1173  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1174 
1175  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1176  // this at some point... jhrg
1177  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1178  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1179  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1180 
1181  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1182  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1183 
1184  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1185  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1186 
1187  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1188  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1189  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1190  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1191 
1192  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1193  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1194 
1195  if (!get_request_xml_base().empty()) {
1196  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1197  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1198 
1199  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1200  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1201  }
1202  }
1203  else {
1204  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1205  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1206 
1207  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1208  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1209  }
1210 
1211  // Print the global attributes
1212  d_attr.print_xml_writer(xml);
1213 
1214  // Print each variable
1215  for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1216 
1217  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1218  // the same.
1219  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1220  // actually the CID of the MIME part that holds the data.
1221  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1222  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1223  throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1224  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)"") < 0)
1225  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1226  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1227  throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
1228  }
1229  else if (!blob.empty() && (get_dap_major() == 3 && get_dap_minor() >= 2) || get_dap_major() >= 4) {
1230  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1231  throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1232  string cid="cid:" + blob;
1233  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)cid.c_str()) < 0)
1234  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1235  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1236  throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1237  }
1238 
1239  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1240  throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
1241 
1242  out << xml.get_doc();// << ends;// << endl;
1243 }
1244 
1245 // Used by DDS::send() when returning data from a function call.
1260 bool
1262 {
1263  // The dataset must have a name
1264  if (name == "") {
1265  cerr << "A dataset must have a name" << endl;
1266  return false;
1267  }
1268 
1269  string msg;
1270  if (!unique_names(vars, name, "Dataset", msg))
1271  return false;
1272 
1273  if (all)
1274  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1275  if (!(*i)->check_semantics(msg, true))
1276  return false;
1277 
1278  return true;
1279 }
1280 
1306 bool
1307 DDS::mark(const string &n, bool state)
1308 {
1310 
1311  DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1312 
1313  BaseType *variable = var(n, s);
1314  if (!variable) {
1315  DBG2(cerr << "Could not find variable " << n << endl);
1316  delete s; s = 0;
1317  return false;
1318  }
1319  variable->set_send_p(state);
1320 
1321  DBG2(cerr << "DDS::mark: Set variable " << variable->name()
1322  << " (a " << variable->type_name() << ")" << endl);
1323 
1324  // Now check the btp_stack and run BaseType::set_send_p for every
1325  // BaseType pointer on the stack. Using BaseType::set_send_p() will
1326  // set the property for a Constructor but not its contained variables
1327  // which preserves the semantics of projecting just one field.
1328  while (!s->empty()) {
1329  s->top()->BaseType::set_send_p(state);
1330 
1331  DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
1332  << " (a " << s->top()->type_name() << ")" << endl);
1333  string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1334  string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1335  DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1336 
1337  s->pop();
1338  }
1339 
1340  delete s ; s = 0;
1341 
1342  return true;
1343 }
1344 
1350 void
1351 DDS::mark_all(bool state)
1352 {
1353  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1354  (*i)->set_send_p(state);
1355 }
1356 
1364 void
1365 DDS::dump(ostream &strm) const
1366 {
1367  strm << DapIndent::LMarg << "DDS::dump - ("
1368  << (void *)this << ")" << endl ;
1369  DapIndent::Indent() ;
1370  strm << DapIndent::LMarg << "name: " << name << endl ;
1371  strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1372  strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1373  strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1374  strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1375 
1376  strm << DapIndent::LMarg << "global attributes:" << endl ;
1377  DapIndent::Indent() ;
1378  d_attr.dump(strm) ;
1380 
1381  if (vars.size()) {
1382  strm << DapIndent::LMarg << "vars:" << endl ;
1383  DapIndent::Indent() ;
1384  Vars_citer i = vars.begin() ;
1385  Vars_citer ie = vars.end() ;
1386  for (; i != ie; i++) {
1387  (*i)->dump(strm) ;
1388  }
1390  }
1391  else {
1392  strm << DapIndent::LMarg << "vars: none" << endl ;
1393  }
1394 
1396 }
1397 
1398 } // namespace libdap