libdap++  Updated for version 3.11.7
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 25915 2012-10-24 00:14:58Z 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  if (d_container) {
500  d_container->add_var_nocopy(bt);
501  }
502  else {
503  vars.push_back(bt);
504  }
505 }
506 
507 
514 void
515 DDS::del_var(const string &n)
516 {
517  if( d_container )
518  {
519  d_container->del_var( n ) ;
520  return ;
521  }
522 
523  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
524  if ((*i)->name() == n) {
525  BaseType *bt = *i ;
526  vars.erase(i) ;
527  delete bt ; bt = 0;
528  return;
529  }
530  }
531 }
532 
537 void
539 {
540  if (i != vars.end()) {
541  BaseType *bt = *i ;
542  vars.erase(i) ;
543  delete bt ; bt = 0;
544  }
545 }
546 
553 void
555 {
556  for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
557  BaseType *bt = *i_tmp ;
558  delete bt ; bt = 0;
559  }
560  vars.erase(i1, i2) ;
561 }
562 
570 BaseType *
571 DDS::var(const string &n, BaseType::btp_stack &s)
572 {
573  return var(n, &s);
574 }
594 BaseType *
595 DDS::var(const string &n, BaseType::btp_stack *s)
596 {
597  string name = www2id(n);
598  if( d_container )
599  return d_container->var( name, false, s ) ;
600 
601  BaseType *v = exact_match(name, s);
602  if (v)
603  return v;
604 
605  return leaf_match(name, s);
606 }
607 
608 BaseType *
610 {
611  DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
612 
613  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
614  BaseType *btp = *i;
615  DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
616  // Look for the name in the dataset's top-level
617  if (btp->name() == n) {
618  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
619  return btp;
620  }
621 
622  if (btp->is_constructor_type()) {
623  BaseType *found = btp->var(n, false, s);
624  if (found) {
625  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
626  return found;
627  }
628  }
629 #if STRUCTURE_ARRAY_SYNTAX_OLD
630  if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
631  s->push(btp);
632  BaseType *found = btp->var()->var(n, false, s);
633  if (found) {
634  DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
635  return found;
636  }
637  }
638 #endif
639  }
640 
641  return 0; // It is not here.
642 }
643 
644 BaseType *
645 DDS::exact_match(const string &name, BaseType::btp_stack *s)
646 {
647  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
648  BaseType *btp = *i;
649  DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
650  // Look for the name in the current ctor type or the top level
651  if (btp->name() == name) {
652  DBG2(cerr << "Found " << name << " in: " << btp << endl);
653  return btp;
654  }
655  }
656 
657  string::size_type dot_pos = name.find(".");
658  if (dot_pos != string::npos) {
659  string aggregate = name.substr(0, dot_pos);
660  string field = name.substr(dot_pos + 1);
661 
662  BaseType *agg_ptr = var(aggregate, s);
663  if (agg_ptr) {
664  DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
665  return agg_ptr->var(field, true, s);
666  }
667  else
668  return 0; // qualified names must be *fully* qualified
669  }
670 
671  return 0; // It is not here.
672 }
673 
674 
679 {
680  return vars.begin();
681 }
682 
685 {
686  return vars.rbegin();
687 }
688 
691 {
692  return vars.end() ;
693 }
694 
697 {
698  return vars.rend() ;
699 }
700 
706 {
707  return vars.begin() + i;
708 }
709 
713 BaseType *
715 {
716  return *(vars.begin() + i);
717 }
718 
723 void
725 {
726  vars.insert(i, ptr->ptr_duplicate());
727 }
728 
736 void
738 {
739  vars.insert(i, ptr);
740 }
741 
743 int
745 {
746  return vars.size();
747 }
748 
749 void
751 {
752 #ifndef WIN32
753  alarm(d_timeout);
754 #endif
755 }
756 
757 void
759 {
760 #ifndef WIN32
761  d_timeout = alarm(0);
762 #endif
763 }
764 
765 void
767 {
768  // Has no effect under win32
769  d_timeout = t;
770 }
771 
772 int
774 {
775  // Has to effect under win32
776  return d_timeout;
777 }
778 
780 void
782 {
783  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
784  if ((*i)->type() == dods_sequence_c)
785  dynamic_cast<Sequence&>(**i).set_leaf_sequence();
786  else if ((*i)->type() == dods_structure_c)
787  dynamic_cast<Structure&>(**i).set_leaf_sequence();
788  }
789 }
790 
792 void
793 DDS::parse(string fname)
794 {
795  FILE *in = fopen(fname.c_str(), "r");
796 
797  if (!in) {
798  throw Error(cannot_read_file, "Could not open: " + fname);
799  }
800 
801  try {
802  parse(in);
803  fclose(in);
804  }
805  catch (Error &e) {
806  fclose(in);
807  throw ;
808  }
809 }
810 
811 
813 void
814 DDS::parse(int fd)
815 {
816 #ifdef WIN32
817  FILE *in = fdopen(_dup(fd), "r");
818 #else
819  FILE *in = fdopen(dup(fd), "r");
820 #endif
821 
822  if (!in) {
823  throw InternalErr(__FILE__, __LINE__, "Could not access file.");
824  }
825 
826  try {
827  parse(in);
828  fclose(in);
829  }
830  catch (Error &e) {
831  fclose(in);
832  throw ;
833  }
834 }
835 
842 void
843 DDS::parse(FILE *in)
844 {
845  if (!in) {
846  throw InternalErr(__FILE__, __LINE__, "Null input stream.");
847  }
848 
849  void *buffer = dds_buffer(in);
850  dds_switch_to_buffer(buffer);
851 
852  parser_arg arg(this);
853 
854  bool status = ddsparse((void *) & arg) == 0;
855 
856  dds_delete_buffer(buffer);
857 
858  DBG2(cout << "Status from parser: " << status << endl);
859 
860  // STATUS is the result of the parser function; if a recoverable error
861  // was found it will be true but arg.status() will be false.
862  if (!status || !arg.status()) {// Check parse result
863  if (arg.error())
864  throw *arg.error();
865  }
866 }
867 
868 #if FILE_METHODS
869 
870 void
871 DDS::print(FILE *out)
872 {
873 #if 0
874  ostringstream oss;
875  print(oss);
876 
877  fwrite(oss.str().c_str(), oss.str().length(), 1, out);
878 #else
879  fprintf(out, "Dataset {\n") ;
880 
881  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
882  (*i)->print_decl(out) ;
883  }
884 
885  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
886 
887  return ;
888 #endif
889 }
890 #endif
891 
893 void
894 DDS::print(ostream &out)
895 {
896  out << "Dataset {\n" ;
897 
898  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
899  (*i)->print_decl(out) ;
900  }
901 
902  out << "} " << id2www(name) << ";\n" ;
903 
904  return ;
905 }
906 
916 void
917 DDS::print_das(ostream &out)
918 {
919  out << "Attributes {\n" ;
920 
921  d_attr.print(out, " ");
922  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
923  (*i)->get_attr_table().print(out, " ");
924  }
925 
926  out << "}\n" ;
927 }
928 
929 #if FILE_METHODS
930 
940 void
942 {
943  fprintf(out, "Dataset {\n") ;
944 
945  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
946  // for each variable, indent with four spaces, print a trailing
947  // semicolon, do not print debugging information, print only
948  // variables in the current projection.
949  (*i)->print_decl(out, " ", true, false, true) ;
950  }
951 
952  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
953 
954  return;
955 }
956 #endif
957 
968 void
970 {
971  out << "Dataset {\n" ;
972 
973  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
974  // for each variable, indent with four spaces, print a trailing
975  // semicolon, do not print debugging information, print only
976  // variables in the current projection.
977  (*i)->print_decl(out, " ", true, false, true) ;
978  }
979 
980  out << "} " << id2www(name) << ";\n" ;
981 
982  return;
983 }
984 
985 #if FILE_METHODS
986 class VariablePrintXML : public unary_function<BaseType *, void>
987 {
988  FILE *d_out;
989  bool d_constrained;
990 public:
991  VariablePrintXML(FILE *out, bool constrained)
992  : d_out(out), d_constrained(constrained)
993  {}
994  void operator()(BaseType *bt)
995  {
996  bt->print_xml(d_out, " ", d_constrained);
997  }
998 };
999 
1011 void
1012 DDS::print_xml(FILE *out, bool constrained, const string &blob)
1013 {
1014  ostringstream oss;
1015  print_xml_writer(oss, constrained, blob);
1016 
1017  string doc = oss.str();
1018  fwrite(doc.data(), 1, doc.length(), out);
1019 
1020 #if 0
1021  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1022 
1023  fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
1024 
1025  fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1026 
1027  fprintf(out,"method=\"FILE*\"\n");
1028  fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
1029  fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
1030 
1031  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1032  // this at some point... jhrg
1033  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1034  fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
1035 
1036  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
1038  }
1039  else {
1040  fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
1041  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
1043  }
1044 
1045 
1046  d_attr.print_xml(out, " ", constrained);
1047 
1048  fprintf(out, "\n");
1049 
1050  for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
1051 
1052  fprintf(out, "\n");
1053 
1054  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1055  // the same. jhrg
1056  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1057  fprintf(out, " <dataBLOB href=\"\"/>\n");
1058  }
1059  else if (!blob.empty()
1060  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1061  || get_dap_major() >= 4) {
1062  fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str());
1063  }
1064 
1065 
1066  fprintf(out, "</Dataset>\n");
1067 #endif
1068 }
1069 #endif
1070 
1071 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
1072 {
1073  ostream &d_out;
1074  bool d_constrained;
1075 public:
1076  VariablePrintXMLStrm(ostream &out, bool constrained)
1077  : d_out(out), d_constrained(constrained)
1078  {}
1079  void operator()(BaseType *bt)
1080  {
1081  bt->print_xml(d_out, " ", d_constrained);
1082  }
1083 };
1084 
1096 void
1097 DDS::print_xml(ostream &out, bool constrained, const string &blob)
1098 {
1099  print_xml_writer(out, constrained, blob);
1100 
1101 #if 0
1102  out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
1103 
1104  out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
1105 
1106  out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
1107 
1108  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1109  // this at some point... jhrg
1110  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1111  out << "xsi:schemaLocation=\"" << c_dap32_namespace
1112  << " " << c_default_dap32_schema_location << "\"\n" ;
1113 
1114  out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
1115  out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
1116 
1117  out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
1118  out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
1119 
1120  out << "dapVersion=\"" << get_dap_major() << "."
1121  << get_dap_minor() << "\"";
1122 
1123  if (!get_request_xml_base().empty()) {
1124  out << "\n";
1125  out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
1126  out << "xml:base=\"" << get_request_xml_base() << "\"";
1127  }
1128 
1129  // Close the Dataset element
1130  out << ">\n";
1131  }
1132  else {
1133  out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
1134  out << "xsi:schemaLocation=\"" << c_dap20_namespace
1135  << " " << c_default_dap20_schema_location << "\">\n\n" ;
1136  }
1137 
1138  d_attr.print_xml(out, " ", constrained);
1139 
1140  out << "\n" ;
1141 
1142  for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
1143 
1144  out << "\n" ;
1145 
1146  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1147  // the same.
1148  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1149  // actually the CID of the MIME part that holds the data.
1150  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1151  out << " <dataBLOB href=\"\"/>\n" ;
1152  }
1153  else if (!blob.empty()
1154  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1155  || get_dap_major() >= 4) {
1156  out << " <blob href=\"cid:" << blob << "\"/>\n";
1157  }
1158 
1159  out << "</Dataset>\n" ;
1160 #endif
1161 }
1162 
1163 class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1164 {
1165  XMLWriter &d_xml;
1166  bool d_constrained;
1167 public:
1168  VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
1169  : d_xml(xml), d_constrained(constrained)
1170  {}
1171  void operator()(BaseType *bt)
1172  {
1173  bt->print_xml_writer(d_xml, d_constrained);
1174  }
1175 };
1176 
1177 
1178 void
1179 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
1180 {
1181  XMLWriter xml(" ");
1182 
1183  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1184  throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1185  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name.c_str()) < 0)
1186  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1187  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1188  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1189 
1190  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1191  // this at some point... jhrg
1192  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1193  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1194  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1195 
1196  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1197  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1198 
1199  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1200  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1201 
1202  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1203  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1204  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1205  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1206 
1207  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1208  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1209 
1210  if (!get_request_xml_base().empty()) {
1211  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1212  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1213 
1214  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1215  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1216  }
1217  }
1218  else {
1219  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1220  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1221 
1222  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1223  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1224  }
1225 
1226  // Print the global attributes
1227  d_attr.print_xml_writer(xml);
1228 
1229  // Print each variable
1230  for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1231 
1232  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1233  // the same.
1234  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1235  // actually the CID of the MIME part that holds the data.
1236  // FIXME cerr
1237  cerr << "blob: " << blob << ", " << "dap major, minor: " << get_dap_major() << ", " << get_dap_minor() << endl;
1238 
1239  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1240  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1241  throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1242  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)"") < 0)
1243  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1244  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1245  throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
1246  }
1247  else if (!blob.empty() && (get_dap_major() == 3 && get_dap_minor() >= 2) || get_dap_major() >= 4) {
1248  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1249  throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1250  string cid="cid:" + blob;
1251  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)cid.c_str()) < 0)
1252  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1253  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1254  throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1255  }
1256 
1257  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1258  throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
1259 
1260  out << xml.get_doc();// << ends;// << endl;
1261 }
1262 
1263 // Used by DDS::send() when returning data from a function call.
1278 bool
1280 {
1281  // The dataset must have a name
1282  if (name == "") {
1283  cerr << "A dataset must have a name" << endl;
1284  return false;
1285  }
1286 
1287  string msg;
1288  if (!unique_names(vars, name, "Dataset", msg))
1289  return false;
1290 
1291  if (all)
1292  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1293  if (!(*i)->check_semantics(msg, true))
1294  return false;
1295 
1296  return true;
1297 }
1298 
1324 bool
1325 DDS::mark(const string &n, bool state)
1326 {
1328 
1329  DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1330 
1331  BaseType *variable = var(n, s);
1332  if (!variable) {
1333  DBG2(cerr << "Could not find variable " << n << endl);
1334  delete s; s = 0;
1335  return false;
1336  }
1337  variable->set_send_p(state);
1338 
1339  DBG2(cerr << "DDS::mark: Set variable " << variable->name()
1340  << " (a " << variable->type_name() << ")" << endl);
1341 
1342  // Now check the btp_stack and run BaseType::set_send_p for every
1343  // BaseType pointer on the stack. Using BaseType::set_send_p() will
1344  // set the property for a Constructor but not its contained variables
1345  // which preserves the semantics of projecting just one field.
1346  while (!s->empty()) {
1347  s->top()->BaseType::set_send_p(state);
1348 
1349  DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
1350  << " (a " << s->top()->type_name() << ")" << endl);
1351  // FIXME get_parent() hosed?
1352 #if 1
1353  string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1354  string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1355  DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1356 #endif
1357  s->pop();
1358  }
1359 
1360  delete s ; s = 0;
1361 
1362  return true;
1363 }
1364 
1370 void
1371 DDS::mark_all(bool state)
1372 {
1373  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1374  (*i)->set_send_p(state);
1375 }
1376 
1384 void
1385 DDS::dump(ostream &strm) const
1386 {
1387  strm << DapIndent::LMarg << "DDS::dump - ("
1388  << (void *)this << ")" << endl ;
1389  DapIndent::Indent() ;
1390  strm << DapIndent::LMarg << "name: " << name << endl ;
1391  strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1392  strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1393  strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1394  strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1395 
1396  strm << DapIndent::LMarg << "global attributes:" << endl ;
1397  DapIndent::Indent() ;
1398  d_attr.dump(strm) ;
1400 
1401  if (vars.size()) {
1402  strm << DapIndent::LMarg << "vars:" << endl ;
1403  DapIndent::Indent() ;
1404  Vars_citer i = vars.begin() ;
1405  Vars_citer ie = vars.end() ;
1406  for (; i != ie; i++) {
1407  (*i)->dump(strm) ;
1408  }
1410  }
1411  else {
1412  strm << DapIndent::LMarg << "vars: none" << endl ;
1413  }
1414 
1416 }
1417 
1418 } // namespace libdap
std::vector< entry * >::iterator Attr_iter
Definition: AttrTable.h:237
const string c_dap32_namespace
Definition: DDS.cc:92
static void UnIndent()
Definition: DapIndent.cc:49
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:871
virtual void add_var_nocopy(BaseType *bt, Part part=nil)
Definition: Structure.cc:244
const string c_dap_32_n_sl
Definition: DDS.cc:95
virtual Attr_iter attr_end()
Definition: AttrTable.cc:724
DDS(BaseTypeFactory *factory, const string &n="")
Definition: DDS.cc:148
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition: DDS.cc:737
int ddsparse(void *arg)
const string c_dap20_namespace
Definition: DDS.cc:91
Contains the attributes for a dataset.
Definition: AttrTable.h:150
#define not_used
Definition: config.h:853
void dds_delete_buffer(void *buffer)
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: Structure.cc:416
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition: DDS.cc:705
string get_error_message() const
Definition: Error.cc:279
const string c_default_dap32_schema_location
Definition: DDS.cc:89
BaseType * leaf_match(const string &name, BaseType::btp_stack *s=0)
Definition: DDS.cc:609
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition: DDS.cc:724
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:678
virtual void print_xml(FILE *out, string pad=" ", bool constrained=false)
Definition: AttrTable.cc:1303
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition: DDS.h:280
string id2xml(string in, const string &not_allowed)
Definition: escaping.cc:270
void set_timeout(int t)
Definition: DDS.cc:766
int get_request_size(bool constrained)
Get the estimated response size.
Definition: DDS.cc:449
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition: DDS.cc:571
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:201
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1012
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1409
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1233
std::vector< BaseType * >::const_iterator Vars_citer
Definition: DDS.h:219
void timeout_off()
Definition: DDS.cc:758
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition: DDS.cc:1179
virtual void add_var(BaseType *bt, Part part=nil)
Definition: Structure.cc:221
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:493
Holds a structure (aggregate) type.
Definition: Structure.h:100
Vars_riter var_rend()
Return a reverse iterator.
Definition: DDS.cc:696
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:242
#define DBG2(x)
Definition: debug.h:73
int num_var()
Returns the number of variables in the DDS.
Definition: DDS.cc:744
std::vector< BaseType * >::reverse_iterator Vars_riter
Definition: DDS.h:221
stack< BaseType * > btp_stack
Definition: BaseType.h:218
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition: DDS.cc:1325
A class for software fault reporting.
Definition: InternalErr.h:64
virtual bool is_vector_type()
Returns true if the instance is a vector (i.e., array) type variable.
Definition: BaseType.cc:324
void parse(string fname)
Parse a DDS from a file with the given name.
Definition: DDS.cc:793
DDS & operator=(const DDS &rhs)
Definition: DDS.cc:176
virtual bool is_constructor_type()
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
Definition: BaseType.cc:356
xmlTextWriterPtr get_writer()
Definition: XMLWriter.h:36
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:660
#define DBG(x)
Definition: debug.h:58
string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:252
virtual ~DDS()
Definition: DDS.cc:166
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition: DDS.h:263
virtual void set_send_p(bool state)
Definition: BaseType.cc:517
void mark_all(bool state)
Definition: DDS.cc:1371
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:414
static void Indent()
Definition: DapIndent.cc:43
#define cannot_read_file
Definition: Error.h:66
const string c_xml_namespace
Definition: DDS.cc:99
std::vector< BaseType * >::iterator Vars_iter
Definition: DDS.h:220
void print_das(ostream &out)
Definition: DDS.cc:917
virtual AttrTable & get_attr_table()
Definition: DDS.cc:274
BaseType * get_var_index(int i)
Get a variable.
Definition: DDS.cc:714
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition: DDS.cc:1279
void * dds_buffer(FILE *fp)
void set_dap_version(const string &version_string)
Definition: DDS.cc:337
Structure * container()
Definition: DDS.cc:431
Error * error()
Definition: parser.h:93
string container_name()
Definition: DDS.cc:395
virtual void del_var(const string &name)
Definition: Structure.cc:261
void dds_switch_to_buffer(void *new_buffer)
string name() const
Returns the name of the class instance.
Definition: BaseType.cc:210
virtual AttrTable * get_top_level_attributes()
Returns the top most set of attributes.
Definition: DAS.h:147
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:716
virtual BaseType * ptr_duplicate()=0
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:218
void timeout_on()
Definition: DDS.cc:750
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:690
BaseType * exact_match(const string &name, BaseType::btp_stack *s=0)
Definition: DDS.cc:645
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:781
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:78
const string c_default_dap20_schema_location
Definition: DDS.cc:88
const char * get_doc()
Definition: XMLWriter.cc:80
void ddsrestart(FILE *yyin)
void set_dap_minor(int p)
Set the DAP minor version (typically using info from the client)
Definition: DDS.cc:319
void set_dataset_name(const string &n)
Definition: DDS.cc:265
The basic data type for the DODS DAP types.
Definition: BaseType.h:194
libdap base object for common functionality of libdap objects
Definition: DapObj.h:55
Pass parameters by reference to a parser.
Definition: parser.h:68
void del_var(const string &n)
Removes a variable from the DDS.
Definition: DDS.cc:515
bool unique_names(vector< BaseType * > l, const string &var_name, const string &type_name, string &msg)
Definition: util.cc:120
virtual void dump(ostream &strm) const
dumps information about this object
Definition: AttrTable.cc:1483
Vars_riter var_rbegin()
Return a reverse iterator.
Definition: DDS.cc:684
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
const string grddl_transformation_dap32
Definition: DDS.cc:97
int get_dap_minor() const
Get the DAP minor version as sent by the client.
Definition: DDS.h:265
A class for error processing.
Definition: Error.h:90
string get_dataset_name() const
Definition: DDS.cc:258
void duplicate(const DDS &dds)
Definition: DDS.cc:114
void set_dap_major(int p)
Set the DAP major version (typically using info from the client)
Definition: DDS.cc:303
string filename()
Definition: DDS.cc:289
int get_timeout()
Definition: DDS.cc:773
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:941
virtual void dump(ostream &strm) const
dumps information about this object
Definition: DDS.cc:1385
virtual string container_name()
Returns the name of the current attribute container when multiple files used to build this DAS...
Definition: DAS.cc:102
string id2www(string in, const string &allowable)
Definition: escaping.cc:151
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:470
const string c_dap_20_n_sl
Definition: DDS.cc:94