libdap  Updated for version 3.19.1
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 using namespace std;
60 
61 namespace libdap {
62 
63 void
64 Grid::m_duplicate(const Grid &s)
65 {
66  // TODO revisit this code once/if the class is switched from using it's
67  // own vars to those in Constructor. jhrg 4/3/13
68 
69  // copy the weak pointer - Constructor will take care of copying
70  // the 'strong' pointers.
71  //d_array_var = s.d_array_var;
72  d_is_array_set = s.d_is_array_set;
73 }
74 
84 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), d_is_array_set(false)
85 {}
86 
98 Grid::Grid(const string &n, const string &d)
99  : Constructor(n, d, dods_grid_c), d_is_array_set(false)
100 {}
101 
103 Grid::Grid(const Grid &rhs) : Constructor(rhs)
104 {
105  m_duplicate(rhs);
106 }
107 
108 Grid::~Grid()
109 {
110  //d_array_var = 0; // Weak pointer; object will be freed by Constructor
111 }
112 
113 BaseType *
115 {
116  return new Grid(*this);
117 }
118 
119 Grid &
120 Grid::operator=(const Grid &rhs)
121 {
122  if (this == &rhs)
123  return *this;
124 
125  // Removed this; it makes this operator= work differently than the rest
126 #if 0
127  delete d_array_var; d_array_var = 0;
128 
129  for (Map_iter i = d_map_vars.begin(); i != d_map_vars.end(); i++) {
130  BaseType *btp = *i ;
131  delete btp ;
132  }
133 #endif
134 
135  dynamic_cast<Constructor &>(*this) = rhs;
136 
137  m_duplicate(rhs);
138 
139  return *this;
140 }
141 
145 void
147 {
148  DBG(cerr << __func__ << "() - BEGIN (name:"<< name() <<
149  ")(type:"<< type_name()<<
150  ")(root:'"<< root->name()<<"':"<<(void*)root <<
151  ")(container:'"<< container->name()<<"':"<< (void *) container<< ")"
152  << endl;);
153 
154  vector<Array*> d4_map_arrays;
155 
156  // We do the Map Arrays first because some people expect to see them
157  // delclared prior to the coverage array the utilizes them - even though that
158  // is not a requirement of DAP4 I did it here to make people happier.
159  // We add the maps arrays to the current container if needed and make a
160  // a vector of them so we can add D4Map objects to our Precious down
161  // below.
162  for (Map_iter i = map_begin(), e = map_end(); i != e; ++i) {
163  DBG(cerr << __func__ << "() - Processing Map Array: '"<< (*i)->name() << "' ("<< (void *)(*i)<< ")" << endl;);
164  // Only add the map/array if it's not already present in the target DAP2 container.
165  // Given the scoping rules for DAP2 and the assumption the DDS is valid, testing for
166  // the same name is good enough. The point here is to be sure to only use the
167  // existing maps. This is an important issue when there are multiple Grids in the same
168  // dataset that utilize the same Map arrays data.
169  Array *the_map_array;;
170  Array *container_map_array = static_cast<Array*>(container->var((*i)->name()));
171  if(!container_map_array){
172  DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the current DAP4 container ("<<container->name()<< ":"<<(void*)container<< "). Let's fix that..." << endl;);
173  // Not in the container, so we check root group
174  Array *root_map_array = static_cast<Array*>(root->var((*i)->name()));
175  if (!root_map_array) {
176  // Not in the root group so we transform a new array and add it to container.
177  DBG(cerr << __func__ << "() - No Map Array '" << (*i)->name() << "' present in the root Group ("<<root->name()<< ":"<<(void*)root<< "). Let's fix that..." << endl;);
178  // transform it and add it to the container
179  (*i)->transform_to_dap4(root, container);
180  // Recover the new dap4 version from the container.
181  the_map_array = static_cast<Array*>(container->var((*i)->name()));
182  DBG(cerr << __func__ << "() - Transformed array '"<< the_map_array->name() <<
183  "' to DAP4 Array (" << (void *) the_map_array << ") added to container: '"<<
184  container->name() <<"'" << endl;);
185  }
186  else {
187  the_map_array = root_map_array;
188  DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
189  (void *) the_map_array << ") present in the root group ("<<root->name()<< ":"<<(void*)root <<
190  ")"<< endl;);
191  }
192  }
193  else {
194  the_map_array = container_map_array;
195  DBG(cerr << __func__ << "() - Located Map Array '" << the_map_array->name() << "' (" <<
196  (void *) the_map_array << ") present in the current DAP4 container ("<<container->name( )<< ":"<<
197  (void*)container<< ")" << endl;);
198  }
199  // We'll use these (below) to make D4Map objects for the coverage
200  d4_map_arrays.push_back(the_map_array);
201  }
202 
203  // Adds the coverage array to the container.
204  array_var()->transform_to_dap4(root, container);
205  // Get the new coverage array
206  BaseType *btp = container->var(array_var()->name());
207  Array *coverage = static_cast<Array*>(btp);
208  DBG(cerr << __func__ << "() - Transformed and added DAP4 coverage Array '"<< coverage->name() <<
209  "' to parent container: '" << container->name() << "'" << endl;);
210 
212 
213  DBG(cerr << __func__ << "() - " << "Coverage Array '"<< coverage->name() << "' attributes: " << endl;
214  XMLWriter xmlw;
215  coverage->get_attr_table().print_dap4(xmlw);
216  cerr << xmlw.get_doc() << endl;);
217 
218  // Add the D4Maps
219  vector<Array*>::iterator d4aItr=d4_map_arrays.begin();
220  vector<Array*>::iterator end=d4_map_arrays.end();
221  for( ; d4aItr!=end ; d4aItr++){
222  Array *the_map_array = *d4aItr;
223  // Here we use the Map Array that we saved the Map
224  // name and Map Array reference for our map.
225  D4Map *d4_map = new D4Map(the_map_array->FQN(), the_map_array, coverage); // bind the 'map' to the coverage
226  coverage->maps()->add_map(d4_map); // bind the coverage to the map
227  // Clear the vector entry to ensure that ~Array doesn't
228  // get called when the (stack declared) vector goes out of scope.
229  *d4aItr = 0;
230  DBG(cerr << __func__ << "() - Added DAP4 Map Array: '"<< d4_map->name() <<
231  "' (" << (void *) d4_map->array() << ") to coverage: '" << coverage->name() << "'" << endl;);
232 
233  }
234  DBG(cerr << __func__ << "() - END (grid:" << name() << ")" << endl;);
235 }
236 
237 
243 bool
245 {
246  return true;
247 }
248 
261 void
263 {
264  if (!bt)
265  throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
266 
267  if (part == array && d_is_array_set/*get_array()*/) {
268  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
269  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
270  }
271 
272  // avoid obvious broken semantics
273  if (!dynamic_cast<Array*>(bt)) {
274  throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
275  }
276 
277  // Set to the clone of bt if we get that far.
278  BaseType* bt_clone = 0;
279 
280  switch (part) {
281 
282  case array: {
283  // Add it as a copy to preserve old semantics. This sets parent too.
284  bt_clone = bt->ptr_duplicate();
285  set_array(static_cast<Array*>(bt_clone));
286  }
287  break;
288 
289  case maps: {
290  bt_clone = bt->ptr_duplicate();
291  bt_clone->set_parent(this);
292  d_vars.push_back(bt_clone);
293  }
294  break;
295 
296  default: {
297  if (!d_is_array_set) {
298  // Add it as a copy to preserve old semantics. This sets parent too.
299  bt_clone = bt->ptr_duplicate();
300  set_array(static_cast<Array*>(bt_clone));
301  }
302  else {
303  bt_clone = bt->ptr_duplicate();
304  bt_clone->set_parent(this);
305  d_vars.push_back(bt_clone);
306  }
307  }
308  break;
309  }
310 }
311 
327 void
329 {
330  if (!bt)
331  throw InternalErr(__FILE__, __LINE__, "Passing NULL pointer as variable to be added.");
332 
333  if (part == array && d_is_array_set/*get_array()*/) {
334  // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part.
335  throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
336  }
337 
338  // avoid obvious broken semantics
339  if (!dynamic_cast<Array*>(bt)) {
340  throw InternalErr(__FILE__, __LINE__, "Grid::add_var(): object is not an Array!");
341  }
342 
343  bt->set_parent(this);
344 
345  switch (part) {
346 
347  case array: {
348  // Refactored to use new set_array ([mjohnson 11 nov 2009])
349  set_array(static_cast<Array*>(bt));
350  }
351  break;
352 
353  case maps: {
354  // FIXME Why is this commented out?
355  //bt->set_parent(this);
356  d_vars.push_back(bt);
357  }
358  break;
359 
360  default: {
361  if (!d_is_array_set) {
362  // Refactored to use new set_array ([mjohnson 11 nov 2009])
363  // avoid obvious broken semantics
364  set_array(static_cast<Array*>(bt));
365  }
366  else {
367  d_vars.push_back(bt);
368  }
369  }
370  break;
371  }
372 }
373 
387 void Grid::set_array(Array* p_new_arr)
388 {
389  if (!p_new_arr) {
390  throw InternalErr(__FILE__, __LINE__, "Grid::set_array(): Cannot set to null!");
391  }
392 
393  // Make sure not same memory, this would be evil.
394  if (p_new_arr == get_array()) {
395  return;
396  }
397 
398  p_new_arr->set_parent(this);
399 
400  // Three cases: 1. There are no variables set for this grid at all
401  // 2. There are maps but no array
402  // 3. There is already an array set (and maybe maps).
403  // NB: d_array_var is a weak pointer to the Grid's Array
404  if (d_vars.size() == 0) {
405  d_vars.push_back(p_new_arr);
406  }
407  else if (!d_is_array_set) {
408  d_vars.insert(d_vars.begin(), p_new_arr);
409  }
410  else {
411  // clean out old array
412  delete get_array();
413  d_vars[0] = p_new_arr;
414  }
415 
416  d_is_array_set = true;
417 #if 0
418  // store the array pointer locally
419  d_array_var = p_new_arr;
420 
421  // Set the parent
422  d_array_var->set_parent(this);
423 #endif
424 }
425 
452 Array*
453 Grid::add_map(Array* p_new_map, bool add_as_copy)
454 {
455  if (!p_new_map)
456  throw InternalErr(__FILE__, __LINE__, "Grid::add_map(): cannot have p_new_map null!");
457 
458  if (add_as_copy)
459  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
460 
461  p_new_map->set_parent(this);
462 
463  d_vars.push_back(p_new_map);
464 
465  // return the one that got put into the Grid.
466  return p_new_map;
467 }
468 
481 Array*
482 Grid::prepend_map(Array* p_new_map, bool add_copy)
483 {
484  if (add_copy)
485  {
486  p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
487  }
488 
489  p_new_map->set_parent(this);
490  d_vars.insert(map_begin(), p_new_map);
491 
492  return p_new_map;
493 }
494 
498 BaseType *
500 {
501  //return d_array_var;
502  // FIXME Should really test that the array has not be set; maps might be added first. jhrg 5/9/13
503 #if 0
504  if (d_array_var)
505  cerr << "In array_var(), d_array_var holds a " << d_array_var->type_name() << endl;
506  else
507  cerr << "In array_var(), d_array_var is null" << endl;
508 #endif
509  return d_is_array_set /*d_vars.size() > 0*/ ? *d_vars.begin() : 0;
510 }
511 
515 Array *
517 {
518  return dynamic_cast<Array*>(array_var());
519 }
520 
522 Grid::Map_iter
524 {
525  // The maps are stored in the second and subsequent elements of the
526  // d_var vector<BaseType*> of Constructor _unless_ the Array part
527  // has yet to be set. In the latter case, there are only maps in
528  // d_vars
529  return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.begin() + 1: d_vars.begin();
530 }
531 
534 Grid::Map_iter
536 {
537  return d_vars.end();
538 }
539 
541 Grid::Map_riter
543 {
544  // see above
545  // return d_is_array_set/*(d_array_var != 0)*/ ? d_vars.rbegin() + 1: d_vars.rbegin();
546  return d_vars.rbegin();
547 }
548 
551 Grid::Map_riter
553 {
554  return d_is_array_set ? d_vars.rend() - 1: d_vars.rend();
555 }
556 
560 Grid::Map_iter
562 {
563  // return map_begin() + i;
564  return d_is_array_set ? map_begin() + 1 + i : map_begin() + i;
565 }
566 
582 int
583 Grid::components(bool constrained)
584 {
585  int comp;
586 
587  if (constrained) {
588  comp = get_array()->send_p() ? 1 : 0;
589 
590  for (Map_iter i = map_begin(); i != map_end(); i++) {
591  if ((*i)->send_p()) {
592  comp++;
593  }
594  }
595  }
596  else {
597  comp = d_vars.size();
598  }
599 
600  return comp;
601 }
602 
604 {
605  DBG( cerr << __func__ << "() - BEGIN "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
606 
607  // At should be the attribute table for the Grid
608  AttrTable *at = at_container->get_attr_table(name());
609  if (at) {
610  DBG( cerr << __func__ << "() - Found AttrTable ("<< at->get_name() << ":" << (void*)at<< ")" << endl;);
611  at->set_is_global_attribute(false);
612 
613  // We don't monkey with the data array attributes because it usually just makes
614  // a mess. but:
615  // TODO We should come back and decide if we want to but configuration
616  // controls on this or do something smarter like check for duplicate values
617  // before merging the Array metadata into the Grid metadata
618  // SO - We don't copy the attributes like we used to:
619  //
620  // array_var()->transfer_attributes(at);
621  //
622  // And then to seal the deal we have to
623  // Mark them as not "global" so they don't get copied.
624  AttrTable *dvat = at->get_attr_table(array_var()->name());
625  if(dvat){
626  dvat->set_is_global_attribute(false);
627  }
628 
629  Map_iter map = map_begin();
630  while (map != map_end()) {
631  DBG( cerr << __func__ << "() - Processing Map Array ("<< (*map)->name() << ":" << (void*)(*map)<< ")" << endl;);
632  (*map)->transfer_attributes(at);
633  map++;
634  }
635 
636  // Trick: If an attribute that's within the container 'at' still has its
637  // is_global_attribute property set, then it's not really a global attr
638  // but instead an attribute that belongs to this Grid.
639  AttrTable::Attr_iter at_p = at->attr_begin();
640  while (at_p != at->attr_end()) {
641  if (at->is_global_attribute(at_p)) {
642  DBG( cerr << __func__ << "() - " <<
643  "Adding unclaimed Attribute ("<<
644  at->get_type(at_p)<< ":" << at->get_name(at_p) << ":" << (void*)(*map)<<
645  ") from AttrTable (" << at->get_name() << ":" << (void*)at << ")" <<
646  " to the variable " << type_name() << " " << name() << endl;);
647 
648  if (at->get_attr_type(at_p) == Attr_container)
649  get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
650  else
651  get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
652  }
653 
654  at_p++;
655  }
656  }
657  else {
658  DBG( cerr << __func__ << "() - No AttrTable named '"<< name() << "' was found in at_container ("<<at_container->get_name()<<":" << (void*)at<< ")" << endl;);
659  }
660  DBG( cerr << __func__ << "() - END "<< type_name() << " " << name() << " (at_container:"<< at_container->get_name() << ":"<<(void*)at_container<< ")" << endl;);
661 }
662 
663 // When projected (using whatever the current constraint provides in the way
664 // of a projection), is the object still a Grid?
665 
682 bool
684 {
685  // For each dimension in the Array part, check the corresponding Map
686  // vector to make sure it is present in the projected Grid. If for each
687  // projected dimension in the Array component, there is a matching Map
688  // vector, then the Grid is valid.
689  bool valid = true;
690  Array *a = get_array();
691 
692  // Don't bother checking if the Array component is not included.
693  if (!a->send_p())
694  return false;
695 
696  // If only one part is being sent, it's clearly not a grid (it must be
697  // the array part of the Grid that's being sent (given that the above
698  // test passed and the array is being sent).
699  if (components(true) == 1)
700  return false;
701 
702  Array::Dim_iter d = a->dim_begin() ;
703  Map_iter m = map_begin() ;
704 
705  while (valid && d != a->dim_end() && m != map_end()) {
706  Array &map = dynamic_cast<Array&>(**m);
707  if (a->dimension_size(d, true) && map.send_p()) {
708  // Check the matching Map vector; the Map projection must equal
709  // the Array dimension projection
710  Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
711  valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
712  && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
713  && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
714  }
715  else {
716  valid = false;
717  }
718 
719  d++, m++;
720  }
721 
722  return valid;
723 }
724 
726 void
728 {
730  for (Map_iter m = map_begin(); m != map_end(); ++m)
731  dynamic_cast<Array&>(*(*m)).clear_constraint();
732 }
733 
734 void
735 Grid::print_decl(FILE *out, string space, bool print_semi,
736  bool constraint_info, bool constrained)
737 {
738  ostringstream oss;
739  print_decl(oss, space, print_semi, constraint_info, constrained);
740  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
741 }
742 
743 void
744 Grid::print_decl(ostream &out, string space, bool print_semi,
745  bool constraint_info, bool constrained)
746 {
747  if (constrained && !send_p())
748  return;
749 
750  // See comment for the FILE* version of this method.
751  if (constrained && !projection_yields_grid()) {
752  out << space << "Structure {\n" ;
753 
754  get_array()->print_decl(out, space + " ", true, constraint_info,
755  constrained);
756 
757  for (Map_citer i = map_begin(); i != map_end(); i++) {
758  (*i)->print_decl(out, space + " ", true,
759  constraint_info, constrained);
760  }
761 
762  out << space << "} " << id2www(name()) ;
763  }
764  else {
765  // The number of elements in the (projected) Grid must be such that
766  // we have a valid Grid object; send it as such.
767  out << space << type_name() << " {\n" ;
768 
769  out << space << " Array:\n" ;
770  get_array()->print_decl(out, space + " ", true, constraint_info,
771  constrained);
772 
773  out << space << " Maps:\n" ;
774  for (Map_citer i = map_begin(); i != map_end(); i++) {
775  (*i)->print_decl(out, space + " ", true,
776  constraint_info, constrained);
777  }
778 
779  out << space << "} " << id2www(name()) ;
780  }
781 
782  if (constraint_info) {
783  if (send_p())
784  out << ": Send True";
785  else
786  out << ": Send False";
787  }
788 
789  if (print_semi)
790  out << ";\n" ;
791 
792  return;
793 }
794 
798 void
799 Grid::print_xml(FILE *out, string space, bool constrained)
800 {
801  XMLWriter xml(space);
802  print_xml_writer(xml, constrained);
803  fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
804 }
805 
809 void
810 Grid::print_xml(ostream &out, string space, bool constrained)
811 {
812  XMLWriter xml(space);
813  print_xml_writer(xml, constrained);
814  out << xml.get_doc();
815 }
816 
817 
818 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void>
819 {
820  XMLWriter &d_xml;
821  bool d_constrained;
822  string d_tag;
823 public:
824  PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map")
825  : d_xml(x), d_constrained(c), d_tag(t)
826  {}
827 
828  void operator()(BaseType *btp)
829  {
830  Array *a = dynamic_cast<Array*>(btp);
831  if (!a)
832  throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
833  a->print_xml_writer_core(d_xml, d_constrained, d_tag);
834  }
835 };
836 
837 void
838 Grid::print_xml_writer(XMLWriter &xml, bool constrained)
839 {
840  if (constrained && !send_p())
841  return;
842 
843  if (constrained && !projection_yields_grid()) {
844  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0)
845  throw InternalErr(__FILE__, __LINE__, "Could not write Structure element");
846 
847  if (!name().empty())
848  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
849  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
850 
852 
853  get_array()->print_xml_writer(xml, constrained);
854 
855  for_each(map_begin(), map_end(),
856  PrintGridFieldXMLWriter(xml, constrained, "Array"));
857 
858  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
859  throw InternalErr(__FILE__, __LINE__, "Could not end Structure element");
860  }
861  else {
862  // The number of elements in the (projected) Grid must be such that
863  // we have a valid Grid object; send it as such.
864  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0)
865  throw InternalErr(__FILE__, __LINE__, "Could not write Grid element");
866 
867  if (!name().empty())
868  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
869  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
870 
872 
873  get_array()->print_xml_writer(xml, constrained);
874 
875  for_each(map_begin(), map_end(),
876  PrintGridFieldXMLWriter(xml, constrained, "Map"));
877 
878  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
879  throw InternalErr(__FILE__, __LINE__, "Could not end Grid element");
880  }
881 }
882 
883 void
884 Grid::print_val(FILE *out, string space, bool print_decl_p)
885 {
886  ostringstream oss;
887  print_val(oss, space, print_decl_p);
888  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
889 }
890 
891 void Grid::print_val(ostream &out, string space, bool print_decl_p)
892 {
893  if (print_decl_p) {
894  print_decl(out, space, false);
895  out << " = ";
896  }
897 
898  // If we are printing a value on the client-side, projection_yields_grid
899  // should not be called since we don't *have* a projection without a
900  // Constraint. I think that if we are here and send_p() is not true, then
901  // the value of this function should be ignored. 4/6/2000 jhrg
902  bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
903  if (pyg || !send_p())
904  out << "{ Array: ";
905  else
906  out << "{";
907 
908  get_array()->print_val(out, "", false);
909 
910  if (pyg || !send_p()) out << " Maps: ";
911 
912  for (Map_citer i = map_begin(); i != map_end(); i++, (void) (i != map_end() && out << ", ")) {
913  (*i)->print_val(out, "", false);
914  }
915 
916  out << " }";
917 
918  if (print_decl_p) out << ";\n";
919 }
920 
921 // Grids have ugly semantics.
922 
927 bool
928 Grid::check_semantics(string &msg, bool all)
929 {
930  if (!BaseType::check_semantics(msg))
931  return false;
932 
933  msg = "";
934 
935  if (!get_array()) {
936  msg += "Null grid base array in `" + name() + "'\n";
937  return false;
938  }
939 
940  // Is it an array?
941  if (get_array()->type() != dods_array_c) {
942  msg += "Grid `" + name() + "'s' member `" + get_array()->name() + "' must be an array\n";
943  return false;
944  }
945 
946  Array *av = (Array *)get_array(); // past test above, must be an array
947 
948  // Array must be of a simple_type.
949  if (!av->var()->is_simple_type()) {
950  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
951  return false;
952  }
953 
954  // enough maps?
955  if ((unsigned)d_vars.size()-1 != av->dimensions()) {
956  msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
957  msg += av->name() + "'\n";
958  return false;
959  }
960 
961  const string array_var_name = av->name();
962  Array::Dim_iter asi = av->dim_begin() ;
963  for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++, asi++) {
964 
965  BaseType *mv = *mvi;
966 
967  // check names
968  if (array_var_name == mv->name()) {
969  msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
970  return false;
971  }
972  // check types
973  if (mv->type() != dods_array_c) {
974  msg += "Grid map variable `" + mv->name() + "' is not an array\n";
975  return false;
976  }
977 
978  Array *mv_a = (Array *)mv; // downcast to (Array *)
979 
980  // Array must be of a simple_type.
981  if (!mv_a->var()->is_simple_type()) {
982  msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
983  return false;
984  }
985 
986  // check shape
987  if (mv_a->dimensions() != 1) {// maps must have one dimension
988  msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n";
989  return false;
990  }
991  // size of map must match corresponding array dimension
992  Array::Dim_iter mv_asi = mv_a->dim_begin() ;
993  int mv_a_size = mv_a->dimension_size(mv_asi) ;
994  int av_size = av->dimension_size(asi) ;
995  if (mv_a_size != av_size) {
996  msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '";
997  msg += get_array()->name() + "'s' cooresponding dimension\n";
998  return false;
999  }
1000  }
1001 
1002  if (all) {
1003  if (!get_array()->check_semantics(msg, true))
1004  return false;
1005  for (Map_iter mvi = map_begin(); mvi != map_end(); mvi++) {
1006  if (!(*mvi)->check_semantics(msg, true)) {
1007  return false;
1008  }
1009  }
1010  }
1011 
1012  return true;
1013 }
1014 
1023 void
1024 Grid::dump(ostream &strm) const
1025 {
1026  strm << DapIndent::LMarg << "Grid::dump - ("
1027  << (void *)this << ")" << endl ;
1028  DapIndent::Indent() ;
1029  Constructor::dump(strm) ;
1030 
1031  DapIndent::UnIndent() ;
1032 }
1033 
1034 } // namespace libdap
1035 
libdap::Array::dimension_size
virtual int dimension_size(Dim_iter i, bool constrained=false)
Returns the size of the dimension.
Definition: Array.cc:743
libdap::Grid
Holds the Grid data type.
Definition: Grid.h:122
libdap::Grid::print_xml
virtual void print_xml(ostream &out, string space=" ", bool constrained=false)
Definition: Grid.cc:810
libdap::AttrTable::attr_end
virtual Attr_iter attr_end()
Definition: AttrTable.cc:718
libdap::Grid::add_var_nocopy
virtual void add_var_nocopy(BaseType *bt, Part part)
Definition: Grid.cc:328
libdap::BaseType::ptr_duplicate
virtual BaseType * ptr_duplicate()=0
libdap::BaseType::transform_to_dap4
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: BaseType.cc:215
libdap::XMLWriter
Definition: XMLWriter.h:39
libdap::Grid::print_xml_writer
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Grid.cc:838
libdap::Grid::Grid
Grid(const string &n)
The Grid constructor.
Definition: Grid.cc:84
libdap::Grid::components
virtual int components(bool constrained=false)
Returns the number of components in the Grid object.
Definition: Grid.cc:583
libdap::BaseType::name
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:311
libdap::Array::dimensions
virtual unsigned int dimensions(bool constrained=false)
Return the total number of dimensions in the array.
Definition: Array.cc:720
libdap::InternalErr
A class for software fault reporting.
Definition: InternalErr.h:64
libdap::Part
Part
Names the parts of multi-section constructor data types.
Definition: Type.h:48
libdap::Grid::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Grid.cc:1024
libdap::Array::print_xml_writer
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: Array.cc:1141
libdap::Array::dim_end
Dim_iter dim_end()
Definition: Array.cc:704
libdap::Array::ptr_duplicate
virtual BaseType * ptr_duplicate()
Definition: Array.cc:175
libdap::Array::dimension_start
virtual int dimension_start(Dim_iter i, bool constrained=false)
Return the start index of a dimension.
Definition: Array.cc:776
libdap::Grid::set_array
virtual void set_array(Array *p_new_arr)
Definition: Grid.cc:387
libdap::AttrTable::get_type
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:612
libdap::D4Group
Definition: D4Group.h:43
libdap::D4Map
Definition: D4Maps.h:54
libdap::Vector::var
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:434
libdap::Grid::add_var
virtual void add_var(BaseType *bt, Part part)
Definition: Grid.cc:262
libdap::BaseType::attributes
virtual D4Attributes * attributes()
Definition: BaseType.cc:590
libdap::Array::Dim_iter
std::vector< dimension >::iterator Dim_iter
Definition: Array.h:206
libdap
Definition: AlarmHandler.h:35
libdap::Grid::ptr_duplicate
virtual BaseType * ptr_duplicate()
Definition: Grid.cc:114
libdap::D4Attributes::transform_to_dap4
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
Definition: D4Attributes.cc:195
libdap::Grid::transfer_attributes
virtual void transfer_attributes(AttrTable *at_container)
Definition: Grid.cc:603
libdap::Grid::clear_constraint
virtual void clear_constraint()
Definition: Grid.cc:727
libdap::AttrTable::get_attr_table
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:606
libdap::BaseType::check_semantics
virtual bool check_semantics(string &msg, bool all=false)
Compare an object's current state with the semantics of its type.
Definition: BaseType.cc:1200
libdap::BaseType::send_p
virtual bool send_p()
Should this variable be sent?
Definition: BaseType.cc:545
libdap::Grid::map_end
Map_iter map_end()
Definition: Grid.cc:535
libdap::Constructor::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Constructor.cc:913
libdap::Grid::map_rbegin
Map_riter map_rbegin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:542
libdap::AttrTable::print_xml_writer
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1424
libdap::Grid::projection_yields_grid
virtual bool projection_yields_grid()
Definition: Grid.cc:683
libdap::Array::dim_begin
Dim_iter dim_begin()
Definition: Array.cc:697
libdap::Grid::map_begin
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:523
libdap::BaseType::set_parent
virtual void set_parent(BaseType *parent)
Definition: BaseType.cc:724
libdap::Grid::get_map_iter
Map_iter get_map_iter(int i)
Definition: Grid.cc:561
libdap::Array::clear_constraint
virtual void clear_constraint()
Clears the projection; add each projected dimension explicitly using add_constraint.
Definition: Array.cc:616
libdap::Grid::print_decl
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:744
libdap::Grid::get_array
Array * get_array()
Returns the Grid Array. This method returns the array using an Array*, so no cast is required.
Definition: Grid.cc:516
libdap::AttrTable::get_attr_vector
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:652
libdap::AttrTable
Contains the attributes for a dataset.
Definition: AttrTable.h:142
libdap::Grid::is_dap2_only_type
virtual bool is_dap2_only_type()
Definition: Grid.cc:244
libdap::Constructor
Definition: Constructor.h:43
libdap::AttrTable::print_dap4
void print_dap4(XMLWriter &xml)
Definition: AttrTable.cc:1497
libdap::BaseType::type
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:356
libdap::Grid::add_map
virtual Array * add_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:453
libdap::BaseType::is_simple_type
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition: BaseType.cc:384
libdap::Grid::array_var
BaseType * array_var()
Returns the Grid Array.
Definition: Grid.cc:499
libdap::D4Maps::add_map
void add_map(D4Map *map)
Definition: D4Maps.h:115
libdap::Array::dimension_stride
virtual int dimension_stride(Dim_iter i, bool constrained=false)
Returns the stride value of the constraint.
Definition: Array.cc:825
libdap::Grid::print_val
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Grid.cc:891
libdap::AttrTable::attr_begin
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:710
libdap::Grid::check_semantics
virtual bool check_semantics(string &msg, bool all=false)
Return true if this Grid is well formed.
Definition: Grid.cc:928
libdap::Array::print_val
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: Array.cc:1293
libdap::BaseType::FQN
virtual std::string FQN() const
Definition: BaseType.cc:323
libdap::Grid::transform_to_dap4
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: Grid.cc:146
libdap::Array::print_decl
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:1049
libdap::id2www
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
libdap::BaseType::get_attr_table
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:573
libdap::BaseType
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
libdap::AttrTable::append_container
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:409
libdap::Grid::map_rend
Map_riter map_rend()
Definition: Grid.cc:552
libdap::Array::dimension_stop
virtual int dimension_stop(Dim_iter i, bool constrained=false)
Return the stop index of the constraint.
Definition: Array.cc:800
libdap::AttrTable::get_name
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:237
libdap::AttrTable::get_attr_type
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:620
libdap::BaseType::type_name
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:370
libdap::Grid::prepend_map
virtual Array * prepend_map(Array *p_new_map, bool add_copy)
Definition: Grid.cc:482
libdap::Constructor::var
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
libdap::Array
A multidimensional array of identical data types.
Definition: Array.h:112
libdap::AttrTable::append_attr
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:306