libdap  Updated for version 3.20.6
libdap4 is an implementation of OPeNDAP's DAP protocol.
Grid.cc
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2002,2003 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 // (c) COPYRIGHT URI/MIT 1994-1999
27 // Please read the full copyright statement in the file COPYRIGHT_URI.
28 //
29 // Authors:
30 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31 
32 // implementation for Grid.
33 //
34 // jhrg 9/15/94
35 
36 #include "config.h"
37 
38 // #define DODS_DEBUG
39 
40 #include <sstream>
41 #include <functional>
42 #include <algorithm>
43 
44 #include "Grid.h"
45 #include "DDS.h"
46 #include "Array.h" // for downcasts
47 #include "util.h"
48 #include "InternalErr.h"
49 #include "escaping.h"
50 #include "XDRStreamMarshaller.h"
51 #include "debug.h"
52 
53 #include "XMLWriter.h"
54 #include "DMR.h"
55 #include "D4Group.h"
56 #include "D4Maps.h"
57 #include "D4Attributes.h"
58 
59 #include "DapIndent.h"
60 
61 using namespace std;
62 
63 namespace libdap {
64 
65 void
66 Grid::m_duplicate(const Grid &s)
67 {
68  // TODO revisit this code once/if the class is switched from using it's
69  // own vars to those in Constructor. jhrg 4/3/13
70 
71  // copy the weak pointer - Constructor will take care of copying
72  // the 'strong' pointers.
73  //d_array_var = s.d_array_var;
74  d_is_array_set = s.d_is_array_set;
75 }
76 
86 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
87 {}
88 
100 Grid::Grid(const string &n, const string &d)
101  : Constructor(n, d, dods_grid_c), d_is_array_set(false)
102 {}
103 
105 Grid::Grid(const Grid &rhs) : Constructor(rhs)
106 {
107  m_duplicate(rhs);
108 }
109 
110 Grid::~Grid()
111 {
112  //d_array_var = 0; // Weak pointer; object will be freed by Constructor
113 }
114 
115 BaseType *
117 {
118  return new Grid(*this);
119 }
120 
121 Grid &
122 Grid::operator=(const Grid &rhs)
123 {
124  if (this == &rhs)
125  return *this;
126 
127  // Removed this; it makes this operator= work differently than the rest
128 #if 0
129  delete d_array_var; d_array_var = 0;
130 
131  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
132  BaseType *btp = *i ;
133  delete btp ;
134  }
135 #endif
136 
137  dynamic_cast<Constructor &>(*this) = rhs;
138 
139  m_duplicate(rhs);
140 
141  return *this;
142 }
143 
147 void
149 {
150  DBG(cerr << __func__ << "() - BEGIN (name:"<< name() <<
151  ")(type:"<< type_name()<<
152  ")(root:'"<< root->name()<<"':"<<(void*)root <<
153  ")(container:'"<< container->name()<<"':"<< (void *) container<< ")"
154  << endl;);
155 
156  vector<Array*> d4_map_arrays;
157 
158  // We do the Map Arrays first because some people expect to see them
159  // delclared prior to the coverage array the utilizes them - even though that
160  // is not a requirement of DAP4 I did it here to make people happier.
161  // We add the maps arrays to the current container if needed and make a
162  // a vector of them so we can add D4Map objects to our Precious down
163  // below.
164  for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
165  DBG(cerr << __func__ << "() - Processing Map Array: '"<< (*i)->name() << "' ("<< (void *)(*i)<< ")" << endl;);
166  // Only add the map/array if it's not already present in the target DAP2 container.
167  // Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
168  // the same name is good enough. The point here is to be sure to only use the
169  // existing maps. This is an important issue when there are multiple Grids in the same
170  // dataset that utilize the same Map arrays data.
171  Array *the_map_array;;
172  Array *container_map_array = static_cast<Array*>(container->var((*i)->name()));
173  if(!container_map_array){
174  DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("<<container->name()<< ":"<<(void*)container<< "). Let's fix that..." << endl;);
175  // Not in the container, so we check root group
176  Array *root_map_array = static_cast<Array*>(root->var((*i)->name()));
177  if (!root_map_array) {
178  // Not in the root group so we transform a new array and add it to container.
179  DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("<<root->name()<< ":"<<(void*)root<< "). Let's fix that..." << endl;);
180  // transform it and add it to the container
181  (*i)->transform_to_dap4(root, container);
182  // Recover the new dap4 version from the container.
183  the_map_array = static_cast<Array*>(container->var((*i)->name()));
184  DBG(cerr << __func__ << "() - Transformed array '"<< the_map_array->name() <<
185  "' to DAP4 Array (" << (void *) the_map_array << ") added to container: '"<<
186  container->name() <<"'" << endl;);
187  }
188  else {
189  the_map_array = root_map_array;
190  DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
191  (void *) the_map_array << ") present in the root group ("<<root->name()<< ":"<<(void*)root <<
192  ")"<< endl;);
193  }
194  }
195  else {
196  the_map_array = container_map_array;
197  DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
198  (void *) the_map_array << ") present in the current DAP4 container ("<<container->name( )<< ":"<<
199  (void*)container<< ")" << endl;);
200  }
201  // We'll use these (below) to make D4Map objects for the coverage
202  d4_map_arrays.push_back(the_map_array);
203  }
204 
205  // Adds the coverage array to the container.
206  array_var()->transform_to_dap4(root, container);
207  // Get the new coverage array
208  BaseType *btp = container->var(array_var()->name());
209  Array *coverage = static_cast<Array*>(btp);
210  DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '"<< coverage->name() <<
211  "' to parent container: '" << container->name() << "'" << endl;);
212 
214 
215  DBG(cerr << __func__ << "() - " << "Coverage Array '"<< coverage->name() << "' attributes: " << endl;
216  XMLWriter xmlw;
217  coverage->get_attr_table().print_dap4(xmlw);
218  cerr << xmlw.get_doc() << endl;);
219 
220  // Add the D4Maps
221  vector<Array*>::iterator d4aItr=d4_map_arrays.begin();
222  vector<Array*>::iterator end=d4_map_arrays.end();
223  for( ; d4aItr!=end ; d4aItr++){
224  Array *the_map_array = *d4aItr;
225  // Here we use the Map Array that we saved the Map
226  // name and Map Array reference for our map.
227  D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
228  coverage->maps()->add_map(d4_map); // bind the coverage to the map
229  // Clear the vector entry to ensure that ~Array doesn't
230  // get called when the (stack declared) vector goes out of scope.
231  *d4aItr = 0;
232  DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
233  "' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
234 
235  }
236  DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
237 }
238 
239 
245 bool
247 {
248  return true;
249 }
250 
263 void
265 {
266  if (!bt)
267  throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
268 
269  if (part == array && d_is_array_set/*get_array()*/) {
270  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
271  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
272  }
273 
274  // avoid obvious broken semantics
275  if (!dynamic_cast<Array*>(bt)) {
276  throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
277  }
278 
279  // Set to the clone of bt if we get that far.
280  BaseType* bt_clone = 0;
281 
282  switch (part) {
283 
284  case array: {
285  // Add it as a copy to preserve old semantics. This sets parent too.
286  bt_clone = bt->ptr_duplicate();
287  set_array(static_cast<Array*>(bt_clone));
288  }
289  break;
290 
291  case maps: {
292  bt_clone = bt->ptr_duplicate();
293  bt_clone->set_parent(this);
294  d_vars.push_back(bt_clone);
295  }
296  break;
297 
298  default: {
299  if (!d_is_array_set) {
300  // Add it as a copy to preserve old semantics. This sets parent too.
301  bt_clone = bt->ptr_duplicate();
302  set_array(static_cast<Array*>(bt_clone));
303  }
304  else {
305  bt_clone = bt->ptr_duplicate();
306  bt_clone->set_parent(this);
307  d_vars.push_back(bt_clone);
308  }
309  }
310  break;
311  }
312 }
313 
329 void
331 {
332  if (!bt)
333  throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
334 
335  if (part == array && d_is_array_set/*get_array()*/) {
336  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
337  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
338  }
339 
340  // avoid obvious broken semantics
341  if (!dynamic_cast<Array*>(bt)) {
342  throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
343  }
344 
345  bt->set_parent(this);
346 
347  switch (part) {
348 
349  case array: {
350  // Refactored to use new set_array ([mjohnson 11 nov 2009])
351  set_array(static_cast<Array*>(bt));
352  }
353  break;
354 
355  case maps: {
356  // FIXME Why is this commented out?
357  //bt->set_parent(this);
358  d_vars.push_back(bt);
359  }
360  break;
361 
362  default: {
363  if (!d_is_array_set) {
364  // Refactored to use new set_array ([mjohnson 11 nov 2009])
365  // avoid obvious broken semantics
366  set_array(static_cast<Array*>(bt));
367  }
368  else {
369  d_vars.push_back(bt);
370  }
371  }
372  break;
373  }
374 }
375 
389 void Grid::set_array(Array* p_new_arr)
390 {
391  if (!p_new_arr) {
392  throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
393  }
394 
395  // Make sure not same memory, this would be evil.
396  if (p_new_arr == get_array()) {
397  return;
398  }
399 
400  p_new_arr->set_parent(this);
401 
402  // Three cases: 1. There are no variables set for this grid at all
403  // 2. There are maps but no array
404  // 3. There is already an array set (and maybe maps).
405  // NB: d_array_var is a weak pointer to the Grid's Array
406  if (d_vars.size() == 0) {
407  d_vars.push_back(p_new_arr);
408  }
409  else if (!d_is_array_set) {
410  d_vars.insert(d_vars.begin(), p_new_arr);
411  }
412  else {
413  // clean out old array
414  delete get_array();
415  d_vars[0] = p_new_arr;
416  }
417 
418  d_is_array_set = true;
419 #if 0
420  // store the array pointer locally
421  d_array_var = p_new_arr;
422 
423  // Set the parent
424  d_array_var->set_parent(this);
425 #endif
426 }
427 
454 Array*
455 Grid::add_map(Array* p_new_map, bool add_as_copy)
456 {
457  if (!p_new_map)
458  throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
459 
460  if (add_as_copy)
461  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
462 
463  p_new_map->set_parent(this);
464 
465  d_vars.push_back(p_new_map);
466 
467  // return the one that got put into the Grid.
468  return p_new_map;
469 }
470 
483 Array*
484 Grid::prepend_map(Array* p_new_map, bool add_copy)
485 {
486  if (add_copy)
487  {
488  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
489  }
490 
491  p_new_map->set_parent(this);
492  d_vars.insert(map_begin(), p_new_map);
493 
494  return p_new_map;
495 }
496 
500 BaseType *
502 {
503  //return d_array_var;
504  // FIXME Should really test that the array has not be set; maps might be added first. jhrg 5/9/13
505 #if 0
506  if (d_array_var)
507  cerr << "In array_var(), d_array_var holds a " << d_array_var->type_name() << endl;
508  else
509  cerr << "In array_var(), d_array_var is null" << endl;
510 #endif
511  return d_is_array_set /*d_vars.size() > 0*/ ? *d_vars.begin() : 0;
512 }
513 
517 Array *
519 {
520  return dynamic_cast<Array*>(array_var());
521 }
522 
524 Grid::Map_iter
526 {
527  // The maps are stored in the second and subsequent elements of the
528  // d_var vector<BaseType*> of Constructor _unless_ the Array part
529  // has yet to be set. In the latter case, there are only maps in
530  // d_vars
531  return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.begin() + 1: d_vars.begin();
532 }
533 
536 Grid::Map_iter
538 {
539  return d_vars.end();
540 }
541 
543 Grid::Map_riter
545 {
546  // see above
547  // return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.rbegin() + 1: d_vars.rbegin();
548  return d_vars.rbegin();
549 }
550 
553 Grid::Map_riter
555 {
556  return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
557 }
558 
562 Grid::Map_iter
564 {
565  // return map_begin() + i;
566  return d_is_array_set ? map_begin() + 1 + i : map_begin() + i;
567 }
568 
584 int
585 Grid::components(bool constrained)
586 {
587  int comp;
588 
589  if (constrained) {
590  comp = get_array()->send_p() ? 1 : 0;
591 
592  for (Map_iter i = map_begin(); i != map_end(); i++) {
593  if ((*i)->send_p()) {
594  comp++;
595  }
596  }
597  }
598  else {
599  comp = d_vars.size();
600  }
601 
602  return comp;
603 }
604 
611 {
612  DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
613 
614  // The variable 'at' should be the attribute table for the Grid
615  AttrTable *at = at_container->get_attr_table(name());
616  if (at) {
617  DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
618  at->set_is_global_attribute(false);
619 
620 #if 0
621  // Removing this is left over from a previous version, unknown date.
622  // If the line is added back, some of the DMR round trip tests fail
623  // and the dapreader behavior is changed - tests that build responses
624  // from .dods and .das files fail when they include Grids. jhrg 5/23/18
625  //
626  // See also HYARX-766
628 #endif
629 
630  // If the AttrTable with the name of this Grid (which is also the
631  // name of the Grid's Array) contains a child AttrTable with that
632  // name, mark the attributes as 'not global' and ignore them. This
633  // code has been here for some time; I just added this comment. jhrg 5/23/18
634  AttrTable *dvat = at->get_attr_table(array_var()->name());
635  if (dvat) {
636  dvat->set_is_global_attribute(false);
637  }
638 
639  Map_iter map = map_begin();
640  while (map != map_end()) {
641  (*map)->transfer_attributes(at);
642  map++;
643  }
644 
645  // Trick: If an attribute that's within the container 'at' still has its
646  // is_global_attribute property set, then it's not really a global attr
647  // but instead an attribute that belongs to this Grid.
648  AttrTable::Attr_iter at_p = at->attr_begin();
649  while (at_p != at->attr_end()) {
650  if (at->is_global_attribute(at_p)) {
651  DBG( cerr << __func__ << "() - " <<
652  "Adding unclaimed Attribute ("<<
653  at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
654  ") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
655  " to the variable " << type_name() << " " << name() << endl;);
656 
657  if (at->get_attr_type(at_p) == Attr_container)
658  get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
659  else
660  get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
661  }
662 
663  at_p++;
664  }
665  }
666  else {
667  DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
668  }
669  DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
670 }
671 
672 // When projected (using whatever the current constraint provides in the way
673 // of a projection), is the object still a Grid?
674 
691 bool
693 {
694  // For each dimension in the Array part, check the corresponding Map
695  // vector to make sure it is present in the projected Grid. If for each
696  // projected dimension in the Array component, there is a matching Map
697  // vector, then the Grid is valid.
698  bool valid = true;
699  Array *a = get_array();
700 
701  // Don't bother checking if the Array component is not included.
702  if (!a->send_p())
703  return false;
704 
705  // If only one part is being sent, it's clearly not a grid (it must be
706  // the array part of the Grid that's being sent (given that the above
707  // test passed and the array is being sent).
708  if (components(true) == 1)
709  return false;
710 
711  Array::Dim_iter d = a->dim_begin() ;
712  Map_iter m = map_begin() ;
713 
714  while (valid && d != a->dim_end() && m != map_end()) {
715  Array &map = dynamic_cast<Array&>(**m);
716  if (a->dimension_size(d, true) && map.send_p()) {
717  // Check the matching Map vector; the Map projection must equal
718  // the Array dimension projection
719  Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
720  valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
721  && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
722  && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
723  }
724  else {
725  valid = false;
726  }
727 
728  d++, m++;
729  }
730 
731  return valid;
732 }
733 
735 void
737 {
739  for (Map_iter m = map_begin(); m != map_end(); ++m)
740  dynamic_cast<Array&>(*(*m)).clear_constraint();
741 }
742 
743 void
744 Grid::print_decl(FILE *out, string space, bool print_semi,
745  bool constraint_info, bool constrained)
746 {
747  ostringstream oss;
748  print_decl(oss, space, print_semi, constraint_info, constrained);
749  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
750 }
751 
752 void
753 Grid::print_decl(ostream &out, string space, bool print_semi,
754  bool constraint_info, bool constrained)
755 {
756  if (constrained && !send_p())
757  return;
758 
759  // See comment for the FILE* version of this method.
760  if (constrained && !projection_yields_grid()) {
761  out << space << "Structure {\n" ;
762 
763  get_array()->print_decl(out, space + " ", true, constraint_info,
764  constrained);
765 
766  for (Map_citer i = map_begin(); i != map_end(); i++) {
767  (*i)->print_decl(out, space + " ", true,
768  constraint_info, constrained);
769  }
770 
771  out << space << "} " << id2www(name()) ;
772  }
773  else {
774  // The number of elements in the (projected) Grid must be such that
775  // we have a valid Grid object; send it as such.
776  out << space << type_name() << " {\n" ;
777 
778  out << space << " Array:\n" ;
779  get_array()->print_decl(out, space + " ", true, constraint_info,
780  constrained);
781 
782  out << space << " Maps:\n" ;
783  for (Map_citer i = map_begin(); i != map_end(); i++) {
784  (*i)->print_decl(out, space + " ", true,
785  constraint_info, constrained);
786  }
787 
788  out << space << "} " << id2www(name()) ;
789  }
790 
791  if (constraint_info) {
792  if (send_p())
793  out << ": Send True";
794  else
795  out << ": Send False";
796  }
797 
798  if (print_semi)
799  out << ";\n" ;
800 
801  return;
802 }
803 
807 void
808 Grid::print_xml(FILE *out, string space, bool constrained)
809 {
810  XMLWriter xml(space);
811  print_xml_writer(xml, constrained);
812  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
813 }
814 
818 void
819 Grid::print_xml(ostream &out, string space, bool constrained)
820 {
821  XMLWriter xml(space);
822  print_xml_writer(xml, constrained);
823  out << xml.get_doc();
824 }
825 
826 
827 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
828 {
829  XMLWriter &d_xml;
830  bool d_constrained;
831  string d_tag;
832 public:
833  PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
834  : d_xml(x), d_constrained(c), d_tag(t)
835  {}
836 
837  void operator()(BaseType *btp)
838  {
839  Array *a = dynamic_cast<Array*>(btp);
840  if (!a)
841  throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
842  a->print_xml_writer_core(d_xml, d_constrained, d_tag);
843  }
844 };
845 
846 void
847 Grid::print_xml_writer(XMLWriter &xml, bool constrained)
848 {
849  if (constrained && !send_p())
850  return;
851 
852  if (constrained && !projection_yields_grid()) {
853  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
854  throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
855 
856  if (!name().empty())
857  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
858  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
859 
861 
862  get_array()->print_xml_writer(xml, constrained);
863 
864  for_each(map_begin(), map_end(),
865  PrintGridFieldXMLWriter(xml, constrained, "Array"));
866 
867  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
868  throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
869  }
870  else {
871  // The number of elements in the (projected) Grid must be such that
872  // we have a valid Grid object; send it as such.
873  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
874  throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
875 
876  if (!name().empty())
877  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
878  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
879 
881 
882  get_array()->print_xml_writer(xml, constrained);
883 
884  for_each(map_begin(), map_end(),
885  PrintGridFieldXMLWriter(xml, constrained, "Map"));
886 
887  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
888  throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
889  }
890 }
891 
892 void
893 Grid::print_val(FILE *out, string space, bool print_decl_p)
894 {
895  ostringstream oss;
896  print_val(oss, space, print_decl_p);
897  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
898 }
899 
900 void Grid::print_val(ostream &out, string space, bool print_decl_p)
901 {
902  if (print_decl_p) {
903  print_decl(out, space, false);
904  out << " = ";
905  }
906 
907  // If we are printing a value on the client-side, projection_yields_grid
908  // should not be called since we don't *have* a projection without a
909  // Constraint. I think that if we are here and send_p() is not true, then
910  // the value of this function should be ignored. 4/6/2000 jhrg
911  bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
912  if (pyg || !send_p())
913  out << "{ Array: ";
914  else
915  out << "{";
916 
917  get_array()->print_val(out, "", false);
918 
919  if (pyg || !send_p()) out << " Maps: ";
920 
921  for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
922  (*i)->print_val(out, "", false);
923  }
924 
925  out << " }";
926 
927  if (print_decl_p) out << ";\n";
928 }
929 
930 // Grids have ugly semantics.
931 
936 bool
937 Grid::check_semantics(string &msg, bool all)
938 {
939  if (!BaseType::check_semantics(msg))
940  return false;
941 
942  msg = "";
943 
944  if (!get_array()) {
945  msg += "Null grid base array in `" + name() + "'\n";
946  return false;
947  }
948 
949  // Is it an array?
950  if (get_array()->type() != dods_array_c) {
951  msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
952  return false;
953  }
954 
955  Array *av = (Array *)get_array(); // past test above, must be an array
956 
957  // Array must be of a simple_type.
958  if (!av->var()->is_simple_type()) {
959  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
960  return false;
961  }
962 
963  // enough maps?
964  if ((unsigned)d_vars.size()-1 != av->dimensions()) {
965  msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
966  msg += av->name() + "'\n";
967  return false;
968  }
969 
970  const string array_var_name = av->name();
971  Array::Dim_iter asi = av->dim_begin() ;
972  for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
973 
974  BaseType *mv = *mvi;
975 
976  // check names
977  if (array_var_name == mv->name()) {
978  msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
979  return false;
980  }
981  // check types
982  if (mv->type() != dods_array_c) {
983  msg += "Grid map variable `" + mv->name() + "' is not an array\n";
984  return false;
985  }
986 
987  Array *mv_a = (Array *)mv; // downcast to (Array *)
988 
989  // Array must be of a simple_type.
990  if (!mv_a->var()->is_simple_type()) {
991  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
992  return false;
993  }
994 
995  // check shape
996  if (mv_a->dimensions() != 1) {// maps must have one dimension
997  msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
998  return false;
999  }
1000  // size of map must match corresponding array dimension
1001  Array::Dim_iter mv_asi = mv_a->dim_begin() ;
1002  int mv_a_size = mv_a->dimension_size(mv_asi) ;
1003  int av_size = av->dimension_size(asi) ;
1004  if (mv_a_size != av_size) {
1005  msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
1006  msg += get_array()->name() + "'s' cooresponding dimension\n";
1007  return false;
1008  }
1009  }
1010 
1011  if (all) {
1012  if (!get_array()->check_semantics(msg, true))
1013  return false;
1014  for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
1015  if (!(*mvi)->check_semantics(msg, true)) {
1016  return false;
1017  }
1018  }
1019  }
1020 
1021  return true;
1022 }
1023 
1032 void
1033 Grid::dump(ostream &strm) const
1034 {
1035  strm << DapIndent::LMarg << "Grid::dump - ("
1036  << (void *)this << ")" << endl ;
1037  DapIndent::Indent() ;
1038  Constructor::dump(strm) ;
1039 
1040  DapIndent::UnIndent() ;
1041 }
1042 
1043 } // namespace libdap
1044 
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:1124
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:320
Map_riter map_rend()
Definition: Grid.cc:554
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:711
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:484
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition: Grid.cc:330
virtual BaseType * var(const string &name, bool exact_match=true, btp_stack *s=0)
btp_stack no longer needed; use back pointers (BaseType::get_parent())
Definition: Constructor.cc:267
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
Contains the attributes for a dataset.
Definition: AttrTable.h:142
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Grid.cc:819
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Grid.cc:1033
STL namespace.
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1425
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition: BaseType.cc:393
Map_iter map_end()
Definition: Grid.cc:537
virtual void set_parent(BaseType *parent)
Definition: BaseType.cc:733
top level DAP object to house generic methods
Definition: AISConnect.cc:30
void print_dap4(XMLWriter &xml)
Definition: AttrTable.cc:1498
A class for software fault reporting.
Definition: InternalErr.h:64
Dim_iter dim_end()
Definition: Array.cc:696
virtual std::string FQN() const
Definition: BaseType.cc:332
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition: Grid.cc:585
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:544
virtual void set_array(Array *p_new_arr)
Definition: Grid.cc:389
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:433
virtual bool projection_yields_grid()
Definition: Grid.cc:692
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:525
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:733
virtual BaseType * ptr_duplicate()
Definition: Grid.cc:116
Map_iter get_map_iter(int i)
Definition: Grid.cc:563
virtual void add_var(BaseType *bt, Part part)
Definition: Grid.cc:264
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
virtual void transfer_attributes(AttrTable *at_container)
Definition: Grid.cc:610
virtual void clear_constraint()
Definition: Grid.cc:736
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:607
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:365
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:206
virtual BaseType * ptr_duplicate()
Definition: Array.cc:175
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:812
Holds the Grid data type.
Definition: Grid.h:122
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: BaseType.cc:216
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Prints a DDS entry for the Array.
Definition: Array.cc:1039
virtual D4Attributes * attributes()
Definition: BaseType.cc:599
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Grid.cc:900
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:455
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required...
Definition: Grid.cc:518
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Constructor.cc:913
virtual bool is_dap2_only_type()
Definition: Grid.cc:246
virtual BaseType * ptr_duplicate()=0
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:788
virtual void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition: Grid.cc:753
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:765
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:582
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
Dim_iter dim_begin()
Definition: Array.cc:690
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:379
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition: Grid.cc:937
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Grid.cc:148
BaseType * array_var()
Returns the Grid Array.
Definition: Grid.cc:501
void add_map(D4Map *map)
Definition: D4Maps.h:115
virtual void transfer_attributes(AttrTable *at)
Definition: BaseType.cc:644
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
A multidimensional array of identical data types.
Definition: Array.h:112
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Array.cc:1271
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:554
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Grid.cc:847
Grid(const string &n)
The Grid constructor.
Definition: Grid.cc:86
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition: Array.cc:616
virtual bool check_semantics(string &msg, bool all=false)
Compare an object&#39;s current state with the semantics of its type.
Definition: BaseType.cc:1209