libdap Updated for version 3.21.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4Group.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2013 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#include "config.h"
26
27#include <cassert>
28
29#include <iostream>
30#include <sstream>
31
32#if 0
33
34#include <iomanip>
35
36#include <stdint.h>
37
38#include "crc.h"
39
40#endif
41
42#include "BaseType.h"
43#include "Array.h"
44
45#include "XMLWriter.h"
46#include "D4Attributes.h"
47#include "D4Dimensions.h"
48#include "D4Group.h"
49#include "D4Enum.h"
50
51#include "D4StreamMarshaller.h"
52#include "D4StreamUnMarshaller.h"
53
54#include "escaping.h"
55#include "util.h"
56#include "debug.h"
57
63#undef INCLUDE_SOURCE_BYTE_ORDER
64
65namespace libdap {
66
67void D4Group::m_duplicate(const D4Group &g)
68{
69 DBG(cerr << "In D4Group::m_duplicate for " << g.name() << endl);
70
71 // dims; deep copy, this is the parent
72 if (g.d_dims) {
73 d_dims = new D4Dimensions(*(g.d_dims));
74 d_dims->set_parent(this);
75
76 // Update all of the D4Dimension weak pointers in the Array objects.
77 // This is a hack - we know that Constructor::m_duplicate() has been
78 // called at this point and any Array instances have dimension pointers
79 // that reference the 'old' dimensions (g.d_dims) and not the 'new'
80 // dimensions made above. Scan every array and re-wire the weak pointers.
81 // jhrg 8/15/14
82 Vars_citer vi = d_vars.begin();
83 while (vi != d_vars.end()) {
84 if ((*vi)->type() == dods_array_c)
85 static_cast<Array*>(*vi)->update_dimension_pointers(g.d_dims, d_dims);
86 ++vi;
87 }
88 }
89
90#if 0
91 // Moved this block up inside the if because g.d_dims might be false. jhrg 9/14/15
92 Vars_citer vi = d_vars.begin();
93 while (vi != d_vars.end()) {
94 if ((*vi)->type() == dods_array_c)
95 static_cast<Array*>(*vi)->update_dimension_pointers(g.d_dims, d_dims);
96 ++vi;
97 }
98#endif
99
100 // enums; deep copy
101 if (g.d_enum_defs) d_enum_defs = new D4EnumDefs(*g.d_enum_defs);
102
103 // groups
104 groupsCIter i = g.d_groups.begin();
105 while(i != g.d_groups.end()) {
106 // Only D4Groups are in the d_groups container.
107 D4Group *g = static_cast<D4Group*>((*i++)->ptr_duplicate());
108 add_group_nocopy(g);
109 }
110
111 DBG(cerr << "Exiting D4Group::m_duplicate" << endl);
112}
113
124D4Group::D4Group(const string &name)
125 : Constructor(name, dods_group_c, /*is_dap4*/true), d_dims(0), d_enum_defs(0)
126{}
127
138D4Group::D4Group(const string &name, const string &dataset)
139 : Constructor(name, dataset, dods_group_c, /*is_dap4*/true), d_dims(0), d_enum_defs(0)
140{}
141
143D4Group::D4Group(const D4Group &rhs) : Constructor(rhs), d_dims(0), d_enum_defs(0)
144{
145 DBG(cerr << "In D4Group::copy_ctor for " << rhs.name() << endl);
146 m_duplicate(rhs);
147}
148
149D4Group::~D4Group()
150{
151 delete d_dims;
152 delete d_enum_defs;
153
154 groupsIter i = d_groups.begin();
155 while(i != d_groups.end())
156 delete *i++;
157}
158
159#if 0
160D4Group *
161
162// I think this was a mistake. jhrg 11/17/16
163#endif
164BaseType *
166{
167 return new D4Group(*this);
168}
169
170D4Group &
171D4Group::operator=(const D4Group &rhs)
172{
173 if (this == &rhs)
174 return *this;
175 Constructor::operator=(rhs);
176 m_duplicate(rhs);
177 return *this;
178}
179
186string
188{
189 // The root group is named "/" (always)
190 return (name() == "/") ? "/" : static_cast<D4Group*>(get_parent())->FQN() + name() + "/";
191}
192
193D4Group *
194D4Group::find_child_grp(const string &grp_name)
195{
196 auto g = find_if(grp_begin(), grp_end(),
197 [grp_name](const D4Group *g) { return g->name() == grp_name; });
198 return (g == grp_end()) ? 0: *g;
199}
200
201// TODO Add constraint param? jhrg 11/17/13
202BaseType *
203D4Group::find_first_var_that_uses_dimension(D4Dimension *dim)
204{
205 // for each group, starting with the root group
206 // for each variable in the group that is marked to send and is an array
207 // return the btp if it uses the D4Dimension
208 // if it contains child groups, search those
209 // return the btp if it uses the D4Dimension
210 // return null
211
212 // exhaustive breadth-first search for 'dim
213
214 // root group
215 for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i) {
216 if ((*i)->send_p() && (*i)->type() == dods_array_c) {
217 Array *a = static_cast<Array*>(*i);
218 for (Array::Dim_iter di = a->dim_begin(), de = a->dim_end(); di != de; ++di) {
219 if (a->dimension_D4dim(di) == dim)
220 return a;
221 }
222 }
223 }
224
225 for (groupsIter i = grp_begin(), e = grp_end(); i != e; ++i) {
226 BaseType *btp = (*i)->find_first_var_that_uses_dimension(dim);
227 if (btp) return btp;
228 }
229
230 return 0;
231}
232
233BaseType *
234D4Group::find_first_var_that_uses_enumeration(D4EnumDef *enum_def)
235{
236 // for each group, starting with the root group
237 // for each variable in the group that is marked to send and is an array
238 // return the btp if it uses the D4EnumDef
239 // if it contains child groups, search those
240 // return the btp if it uses the D4EnumDef
241 // return null
242
243 // exhaustive breadth-first search for 'dim
244
245 // root group
246 for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i) {
247 if ((*i)->send_p() && (*i)->type() == dods_enum_c) {
248 D4Enum *e = static_cast<D4Enum*>(*i);
249 if (e->enumeration() == enum_def)
250 return e;
251 }
252 }
253
254 for (groupsIter i = grp_begin(), e = grp_end(); i != e; ++i) {
255 BaseType *btp = (*i)->find_first_var_that_uses_enumeration(enum_def);
256 if (btp) return btp;
257 }
258
259 return 0;
260}
261
271D4Dimension *
272D4Group::find_dim(const string &path)
273{
274 string lpath = path; // get a mutable copy
275
276 // special-case for the root group
277 if (lpath[0] == '/') {
278 if (name() != "/")
279 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
280 else
281 lpath = lpath.substr(1);
282 }
283
284 string::size_type pos = lpath.find('/');
285 if (pos == string::npos) {
286 // name looks like 'bar'
287 return dims()->find_dim(lpath);
288 }
289
290 // name looks like foo/bar/baz where foo and bar must be groups
291 string grp_name = lpath.substr(0, pos);
292 lpath = lpath.substr(pos + 1);
293
294 D4Group *grp = find_child_grp(grp_name);
295 return (grp == 0) ? 0: grp->find_dim(lpath);
296}
297
303Array *
304D4Group::find_map_source(const string &path)
305{
306 BaseType *map_source = m_find_map_source_helper(path);
307
308 // TODO more complete semantic checking jhrg 10/16/13
309 if (map_source && map_source->type() == dods_array_c) return static_cast<Array*>(map_source);
310
311 return 0;
312}
313
319BaseType *
320D4Group::m_find_map_source_helper(const string &path)
321{
322 string lpath = path; // get a mutable copy
323
324 // special-case for the root group
325 if (lpath[0] == '/') {
326 if (name() != "/")
327 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
328 else
329 lpath = lpath.substr(1);
330 }
331 string::size_type pos = lpath.find('/');
332 if (pos == string::npos) {
333 // name looks like 'bar'
334 return var(lpath);
335 }
336
337 // name looks like foo/bar/baz where foo and bar must be groups
338 string grp_name = lpath.substr(0, pos);
339
340 D4Group *grp = find_child_grp(grp_name);
341 lpath = lpath.substr(pos + 1);
342
343 // We need to resolve the case that
344 // many group layers are involved such as /foo/bar/bar2/bar3/.../baz
345 // The following code handles this.
346 // KY 2023-05-21
347 //
348 pos = lpath.find('/');
349
350 if (pos == string::npos)
351 return (grp == nullptr) ? nullptr: grp->var(lpath);
352
353 // Recursively check the child groups until we hit the leaf.
354 while (pos != string::npos) {
355
356 grp_name = lpath.substr(0, pos);
357 grp = grp->find_child_grp(grp_name);
358 lpath = lpath.substr(pos + 1);
359 pos = lpath.find('/');
360 }
361
362 return (grp == nullptr) ? nullptr: grp->var(lpath);
363
364}
365
366D4EnumDef *
367D4Group::find_enum_def(const string &path)
368{
369 string lpath = path; // get a mutable copy
370
371 // special-case for the root group
372 if (lpath[0] == '/') {
373 if (name() != "/")
374 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
375 else
376 lpath = lpath.substr(1);
377 }
378
379 string::size_type pos = lpath.find('/');
380 if (pos == string::npos) {
381 // name looks like 'bar'
382 return enum_defs()->find_enum_def(lpath);
383 }
384
385 // name looks like foo/bar/baz where foo and bar must be groups
386 string grp_name = lpath.substr(0, pos);
387 lpath = lpath.substr(pos + 1);
388
389 D4Group *grp = find_child_grp(grp_name);
390 return (grp == 0) ? 0: grp->enum_defs()->find_enum_def(lpath);
391}
392
400BaseType *
401D4Group::find_var(const string &path)
402{
403 string lpath = path; // get a mutable copy
404
405 // special-case for the root group
406 if (lpath[0] == '/') {
407 if (name() != "/")
408 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
409 else
410 lpath = lpath.substr(1);
411 }
412
413 string::size_type pos = lpath.find('/');
414 if (pos == string::npos) {
415 // New behavior to accommodate cases where the path ends in a group - the
416 // CE is being used to request all the variables in a Group. So, first check
417 // if this is the name of a Group and if so, return that. Otherwise, look in
418 // the Group's Constructor for a matching variable. jhrg 8/3/22
419 D4Group *grp = find_child_grp(lpath);
420 if (grp != nullptr)
421 return grp;
422 else
423 return var(lpath);
424 }
425
426 // name looks like foo/bar/baz where foo and bar must be groups
427 string grp_name = lpath.substr(0, pos);
428 lpath = lpath.substr(pos + 1);
429
430 D4Group *grp = find_child_grp(grp_name);
431 if (grp == nullptr)
432 return nullptr;
433 else if (lpath.empty())
434 return grp;
435 else
436 return grp->find_var(lpath);
437}
438
447long
448D4Group::request_size(bool constrained)
449{
450 return (long) request_size_kb(constrained);
451}
452
467uint64_t D4Group::request_size_kb(bool constrained)
468{
469 uint64_t size = 0;
470 // variables
471 for (auto &btp: d_vars) {
472 if (constrained) {
473 if (btp->send_p())
474 size += btp->width_ll(constrained);
475 }
476 else {
477 size += btp->width_ll(constrained);
478 }
479 }
480
481 size = size / 1024; // Make into kilobytes
482
483 // All the child groups
484 for(auto grp : d_groups)
485 size += grp->request_size_kb(constrained);
486
487 return size;
488}
489
490void
492{
493 groupsIter g = d_groups.begin();
494 while (g != d_groups.end())
495 (*g++)->set_read_p(state);
496
498}
499
500void
502{
503 groupsIter g = d_groups.begin();
504 while (g != d_groups.end())
505 (*g++)->set_send_p(state);
506
508}
509
510void
511D4Group::intern_data(/*Crc32 &checksum, DMR &dmr, ConstraintEvaluator &eval*/)
512{
513 groupsIter g = d_groups.begin();
514 while (g != d_groups.end())
515 (*g++)->intern_data(/*checksum, dmr, eval*/);
516
517 // Specialize how the top-level variables in any Group are sent; include
518 // a checksum for them. A subset operation might make an interior set of
519 // variables, but the parent structure will still be present and the checksum
520 // will be computed for that structure. In other words, DAP4 does not try
521 // to sort out which variables are the 'real' top-level variables and instead
522 // simply computes the CRC for whatever appears as a variable in the root
523 // group.
524 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
525 // Only send the stuff in the current subset.
526 if ((*i)->send_p()) {
527#if 0
528 checksum.Reset();
529#endif
530 (*i)->intern_data(/*checksum, dmr, eval*/);
531#if 0
532 D4Attribute *a = new D4Attribute("DAP4_Checksum_CRC32", attr_str_c);
533
534 ostringstream oss;
535 oss.setf(ios::hex, ios::basefield);
536 oss << setfill('0') << setw(8) << checksum.GetCrc32();
537 a->add_value(oss.str());
538#if INCLUDE_SOURCE_BYTE_ORDER
539 if (um.is_source_big_endian())
540 a->add_value("source:big-endian");
541 else
542 a->add_value("source:little-endian");
543#endif
544 (*i)->attributes()->add_attribute_nocopy(a);
545 DBG(cerr << "CRC32: " << oss.str() << " for " << (*i)->name() << endl);
546#endif
547 }
548 }
549}
550
562void
563D4Group::serialize(D4StreamMarshaller &m, DMR &dmr, /*ConstraintEvaluator &eval,*/ bool filter)
564{
565#if 0
566 // This will call Constructor read which will, for everything but a Sequence,
567 // read all of the data in one shot. However, the serialize() methods for the
568 // Arrays, Structures, etc., also have read() calls in them and those can be
569 // used to control how long the data are in memory, e.g., limiting the lifetime
570 // of a large array and avoiding having overlapping arrays when they are not
571 // needed. For a sequence read() has different semantics. It is called once
572 // for every instance and the read_p flag is not used.
573 if (!read_p())
574 read(); // read() throws Error
575#endif
576
577 groupsIter g = d_groups.begin();
578 while (g != d_groups.end())
579 (*g++)->serialize(m, dmr, filter);
580
581 // Specialize how the top-level variables in any Group are sent; include
582 // a checksum for them. A subset operation might make an interior set of
583 // variables, but the parent structure will still be present and the checksum
584 // will be computed for that structure. In other words, DAP4 does not try
585 // to sort out which variables are the 'real' top-level variables and instead
586 // simply computes the CRC for whatever appears as a variable in the root
587 // group.
588 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
589 // Only send the stuff in the current subset.
590 if ((*i)->send_p()) {
591 m.reset_checksum();
592
593 DBG(cerr << "Serializing variable " << (*i)->type_name() << " " << (*i)->name() << endl);
594 (*i)->serialize(m, dmr, filter);
595
596 DBG(cerr << "Wrote CRC32: " << m.get_checksum() << " for " << (*i)->name() << endl);
597 m.put_checksum();
598 }
599 }
600}
601
603{
604 groupsIter g = d_groups.begin();
605 while (g != d_groups.end()) {
606 DBG(cerr << "Deserializing group " << (*g)->name() << endl);
607 (*g++)->deserialize(um, dmr);
608 }
609 // Specialize how the top-level variables in any Group are received; read
610 // their checksum and store the value in a magic attribute of the variable
611 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
612 DBG(cerr << "Deserializing variable " << (*i)->type_name() << " " << (*i)->name() << endl);
613 (*i)->deserialize(um, dmr);
614
615 D4Attribute *a = new D4Attribute("DAP4_Checksum_CRC32", attr_str_c);
616 string crc = um.get_checksum_str();
617 a->add_value(crc);
618#if INCLUDE_SOURCE_BYTE_ORDER
619 if (um.is_source_big_endian())
620 a->add_value("source:big-endian");
621 else
622 a->add_value("source:little-endian");
623#endif
624 DBG(cerr << "Read CRC32: " << crc << " for " << (*i)->name() << endl);
625 (*i)->attributes()->add_attribute_nocopy(a);
626 }
627}
628
629void
630D4Group::print_dap4(XMLWriter &xml, bool constrained)
631{
632 if (!name().empty() && name() != "/") {
633 // For named groups, if constrained is true only print if this group
634 // has variables that are marked for transmission. For the root group
635 // this test is not made.
636 if (constrained && !send_p())
637 return;
638
639 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) type_name().c_str()) < 0)
640 throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
641
642 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) name().c_str()) < 0)
643 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
644 }
645
646 // dims
647 if (!dims()->empty())
648 dims()->print_dap4(xml, constrained);
649
650 // enums
651 if (!enum_defs()->empty())
652 enum_defs()->print_dap4(xml, constrained);
653
654 // variables
655 Constructor::Vars_iter v = var_begin();
656 while (v != var_end())
657 (*v++)->print_dap4(xml, constrained);
658
659 // attributes
660 attributes()->print_dap4(xml);
661
662 // groups
663 groupsIter g = d_groups.begin();
664 while (g != d_groups.end())
665 (*g++)->print_dap4(xml, constrained);
666
667 if (!name().empty() && name() != "/") {
668 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
669 throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
670 }
671}
672
673void
674D4Group::print_decl(FILE *out, string space, bool print_semi, bool constraint_info, bool constrained)
675{
676 ostringstream oss;
677 print_decl(oss, space, print_semi, constraint_info, constrained);
678 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
679}
680
681void
682D4Group::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained)
683{
684 if (constrained && !send_p())
685 return;
686
687 out << space << type_name() << " {\n" ;
688 for (auto var: d_vars) {
689 var->print_decl(out, space + " ", true, constraint_info, constrained);
690 }
691
692 for (auto grp: d_groups) {
693 grp->print_decl(out, space + " ", true, constraint_info, constrained);
694 }
695
696 out << space << "} " << id2www(name()) ;
697
698 if (constraint_info) { // Used by test drivers only.
699 if (send_p())
700 out << ": Send True";
701 else
702 out << ": Send False";
703 }
704
705 if (print_semi)
706 out << ";\n" ;
707}
708
709void
710D4Group::print_val(FILE *out, string space, bool print_decl_p)
711{
712 ostringstream oss;
713 print_val(oss, space, print_decl_p);
714 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
715}
716
717void
718D4Group::print_val(ostream &out, string space, bool print_decl_p)
719{
720 if (print_decl_p) {
721 print_decl(out, space, false);
722 out << " = " ;
723 }
724
725 out << "{ " ;
726 bool padding_needed = false; // Add padding - which is complex with the two parts. jhrg 8/5/22
727 for (Vars_citer i = d_vars.begin(), e = d_vars.end(); i != e; i++, (void)(i != e && out << ", ")) {
728 (*i)->print_val(out, "", false);
729 padding_needed = true;
730 }
731
732 if (padding_needed)
733 out << " ";
734
735 padding_needed = false;
736 for (auto grp: d_groups) {
737 grp->print_val(out, "", false);
738 padding_needed = true;
739 }
740
741 if (padding_needed)
742 out << " }";
743 else
744 out << "}" ;
745
746 if (print_decl_p)
747 out << ";\n" ;
748}
749
750#if 0
767vector<BaseType *> *
768D4Group::transform_to_dap2(AttrTable *parent_attr_table)
769{
770 return transform_to_dap2(parent_attr_table, false);
771}
772#endif
796vector<BaseType *> *
798{
799 DBG( cerr << __func__ << "() - BEGIN ("<< name() << ")" << endl);
800
801 vector<BaseType *> *results = new vector<BaseType *>(); // LEAK
802
803 // Get the D4Group's attributes
804#if 0
805 AttrTable *group_attrs = attributes()->get_AttrTable(name());
806#else
807 AttrTable *group_attrs = new AttrTable();
808 attributes()->transform_attrs_to_dap2(group_attrs);
809 group_attrs->set_name(name());
810#endif
811
812 // If this is the root group then copy all of its attributes into the parent_attr_table.
813 // The group_attrs AttrTable* above will be replaced by the parent_attr_table.
814 bool is_root = (name() == "/");
815
816 if (is_root) {
817 assert(name() == "/");
818 for (AttrTable::Attr_iter i = group_attrs->attr_begin(), e = group_attrs->attr_end(); i != e; ++i) {
819 if ((*i)->type == Attr_container) {
820 // copy the source container so that the DAS passed in can be
821 // deleted after calling this method.
822 AttrTable *at = new AttrTable(*(*i)->attributes);
823 parent_attr_table->append_container(at, at->get_name());
824 }
825 else {
826 parent_attr_table->append_attr((*i)->name, AttrType_to_String((*i)->type), (*i)->attr,(*i)->is_utf8_str);
827 }
828 }
829 delete group_attrs;
830 group_attrs = parent_attr_table;
831 }
832
833 // Now we process the child variables of this group
834
835 vector<BaseType *> dropped_vars;
836 for (D4Group::Vars_citer i = var_begin(), e = var_end(); i != e; ++i) {
837
838 DBG( cerr << __func__ << "() - Processing member variable '" << (*i)->name() <<
839 "' root: " << (is_root?"true":"false") << endl);
840
841 vector<BaseType *> *new_vars = (*i)->transform_to_dap2(group_attrs);
842 if (new_vars) { // Might be un-mappable
843 // It's not so game on..
844 for (vector<BaseType*>::iterator vi = new_vars->begin(), ve = new_vars->end(); vi != ve; vi++) {
845 string new_name = (is_root ? "" : FQN()) + (*vi)->name();
846 (*vi)->set_name(new_name);
847 (*vi)->set_parent(NULL);
848 results->push_back((*vi));
849#if 0
850 (*vi) = NULL;
851#endif
852 DBG( cerr << __func__ << "() - Added member variable '" << (*i)->name() << "' " <<
853 "to results vector. root: "<< (is_root?"true":"false") << endl);
854 }
855
856 delete new_vars;
857 }
858 else {
859 DBG( cerr << __func__ << "() - Dropping member variable " << (*i)->name() <<
860 " root: " << (is_root?"true":"false") << endl);
861 // Got back a NULL, so we are dropping this var.
862 dropped_vars.push_back(*i);
863 }
864 }
865
866 // Process dropped DAP4 vars
867 DBG( cerr << __func__ << "() - Processing " << dropped_vars.size() << " Dropped Variable(s)" << endl);
868
869 AttrTable *dv_attr_table = make_dropped_vars_attr_table(&dropped_vars);
870 if (dv_attr_table) {
871 group_attrs->append_container(dv_attr_table, dv_attr_table->get_name());
872 }
873
874 // Get all the child groups.
875 for (D4Group::groupsIter gi = grp_begin(), ge = grp_end(); gi != ge; ++gi) {
876 vector<BaseType *> *d2_vars = (*gi)->transform_to_dap2(group_attrs);
877 if (d2_vars) {
878 for (vector<BaseType *>::iterator i = d2_vars->begin(), e = d2_vars->end(); i != e; ++i) {
879 results->push_back(*i);
880 }
881 }
882 delete d2_vars;
883 }
884
885 if (!is_root) {
886 group_attrs->set_name(name());
887 parent_attr_table->append_container(group_attrs, group_attrs->get_name());
888 }
889
890 return results;
891}
892
898bool D4Group::is_dap4_projected(std::vector<std::string> &inventory)
899{
900 bool has_projected_dap4 = false;
901 if(send_p()) {
902 // Groups are a dap4 thing, so if the Group is projected...
903 has_projected_dap4 = true;
904 inventory.emplace_back(type_name() + " " + FQN());
905
906 // Even tho this Group is a projected dap4 variable we still need to
907 // generate an inventory of it's dap4 attributes and projected dap4 child variables
908 // and groups.
909
910 //Inventory the Group's dap4 attributes
911 has_projected_dap4 |= attributes()->has_dap4_types(FQN(), inventory);
912
913 // Process the child variables.
914 for (const auto var: variables()) {
915 has_projected_dap4 |= var->is_dap4_projected(inventory);
916 }
917 // Process the child Groups.
918 for (const auto grp: groups()) {
919 has_projected_dap4 |= grp->is_dap4_projected(inventory);
920 }
921 }
922 return has_projected_dap4;
923
924}
925
926
927} /* namespace libdap */
A multidimensional array of identical data types.
Definition Array.h:123
std::vector< dimension >::iterator Dim_iter
Definition Array.h:241
Contains the attributes for a dataset.
Definition AttrTable.h:154
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:554
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition AttrTable.cc:273
virtual Attr_iter attr_end()
Definition AttrTable.cc:863
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:335
virtual Attr_iter attr_begin()
Definition AttrTable.cc:855
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:266
The basic data type for the DODS DAP types.
Definition BaseType.h:120
virtual bool is_dap4_projected(std::vector< string > &projected_dap4_inventory)
Definition BaseType.cc:1323
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:376
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:317
virtual void print_decl(FILE *out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition BaseType.cc:1009
virtual BaseType * get_parent() const
Definition BaseType.cc:748
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:477
virtual D4Attributes * attributes()
Definition BaseType.cc:596
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:551
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition BaseType.cc:126
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:362
BaseType * var(const string &name, bool exact_match=true, btp_stack *s=nullptr) override
btp_stack no longer needed; use back pointers (BaseType::get_parent())
void set_read_p(bool state) override
Set the 'read_p' property for the Constructor and its members.
void set_send_p(bool state) override
bool read() override
Read the elements of Constructor marked for transmission.
const vector< BaseType * > & variables() const
Vars_iter var_begin()
void transform_attrs_to_dap2(AttrTable *d2_attr_table)
Copy the attributes from this D4Attributes object to a DAP2 AttrTable.
bool has_dap4_types(const std::string &path, std::vector< std::string > &inventory) const
void print_dap4(XMLWriter &xml, bool constrained=false) override
Definition D4Group.cc:630
D4Dimension * find_dim(const string &path)
Find the dimension using a path. Using the DAP4 name syntax, lookup a dimension. The dimension must b...
Definition D4Group.cc:272
void print_val(FILE *out, string space="", bool print_decl_p=true) override
Prints the value of the variable.
Definition D4Group.cc:710
bool is_dap4_projected(std::vector< std::string > &inventory) override
Definition D4Group.cc:898
Array * find_map_source(const string &path)
Given a path to an Array that is also a Map, get that Array.
Definition D4Group.cc:304
BaseType * find_var(const string &name)
Definition D4Group.cc:401
groupsIter grp_begin()
Get an iterator to the start of the values.
Definition D4Group.h:115
void intern_data() override
Read data into this variable.
Definition D4Group.cc:511
void serialize(D4StreamMarshaller &m, DMR &dmr, bool filter=false) override
Serialize a Group.
Definition D4Group.cc:563
uint64_t request_size_kb(bool constrained)
Get the estimated size of a response in kilobytes.
Definition D4Group.cc:467
groupsIter grp_end()
Get an iterator to the end of the values.
Definition D4Group.h:118
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition D4Group.h:84
void set_send_p(bool state) override
Definition D4Group.cc:501
BaseType * ptr_duplicate() override
Definition D4Group.cc:165
void set_read_p(bool state) override
Set the 'read_p' property for the Constructor and its members.
Definition D4Group.cc:491
void print_decl(ostream &out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false) override
Print an ASCII representation of the variable structure.
Definition D4Group.cc:682
D4EnumDefs * enum_defs()
Get the enumerations defined for this Group.
Definition D4Group.h:99
long request_size(bool constrained)
Definition D4Group.cc:448
D4Group(const string &name)
Definition D4Group.cc:124
std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table) override
Transform the D4Group's variables to DAP2 variables.
Definition D4Group.cc:797
std::string FQN() const override
Definition D4Group.cc:187
void deserialize(D4StreamUnMarshaller &um, DMR &dmr) override
Definition D4Group.cc:602
Marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using DAP4's receiv...
virtual void put_checksum()
Write the checksum Write the checksum for the data sent since the last call to reset_checksum() to th...
Read data from the stream made by D4StreamMarshaller.
bool is_source_big_endian() const
Is the data source we are reading from a big-endian machine? We need this because the value of the CR...
A class for software fault reporting.
Definition InternalErr.h:65
top level DAP object to house generic methods
Definition AISConnect.cc:30
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:97
string id2www(string in, const string &allowable)
Definition escaping.cc:153