libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4Group.cc
Go to the documentation of this file.
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 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#include "Array.h"
33#include "BaseType.h"
34
35#include "D4Attributes.h"
36#include "D4Dimensions.h"
37#include "D4Enum.h"
38#include "D4Group.h"
39#include "XMLWriter.h"
40
41#include "D4StreamMarshaller.h"
43
44#include "debug.h"
45#include "escaping.h"
46#include "util.h"
47
53#undef INCLUDE_SOURCE_BYTE_ORDER
54
55namespace libdap {
56
58 DBG(cerr << "In D4Group::m_duplicate for " << g.name() << endl);
59
60 // dims; deep copy, this is the parent
61 if (g.d_dims) {
62 d_dims = new D4Dimensions(*(g.d_dims));
63 d_dims->set_parent(this);
64
65 // Update all of the D4Dimension weak pointers in the Array objects.
66 // This is a hack - we know that Constructor::m_duplicate() has been
67 // called at this point and any Array instances have dimension pointers
68 // that reference the 'old' dimensions (g.d_dims) and not the 'new'
69 // dimensions made above. Scan every array and re-wire the weak pointers.
70 // jhrg 8/15/14
71 Vars_citer vi = d_vars.begin();
72 while (vi != d_vars.end()) {
73 if ((*vi)->type() == dods_array_c)
74 static_cast<Array *>(*vi)->update_dimension_pointers(g.d_dims, d_dims);
75 ++vi;
76 }
77 }
78
79 // enums; deep copy
80 if (g.d_enum_defs)
81 d_enum_defs = new D4EnumDefs(*g.d_enum_defs);
82
83 // groups
84 groupsCIter i = g.d_groups.begin();
85 while (i != g.d_groups.end()) {
86 // Only D4Groups are in the d_groups container.
87 D4Group *g = static_cast<D4Group *>((*i++)->ptr_duplicate());
89 }
90
91 DBG(cerr << "Exiting D4Group::m_duplicate" << endl);
92}
93
104D4Group::D4Group(const string &name) : Constructor(name, dods_group_c, /*is_dap4*/ true), d_dims(0), d_enum_defs(0) {}
105
116D4Group::D4Group(const string &name, const string &dataset)
117 : Constructor(name, dataset, dods_group_c, /*is_dap4*/ true), d_dims(0), d_enum_defs(0) {}
118
120D4Group::D4Group(const D4Group &rhs) : Constructor(rhs), d_dims(0), d_enum_defs(0) {
121 DBG(cerr << "In D4Group::copy_ctor for " << rhs.name() << endl);
122 m_duplicate(rhs);
123}
124
126 delete d_dims;
127 delete d_enum_defs;
128
129 groupsIter i = d_groups.begin();
130 while (i != d_groups.end())
131 delete *i++;
132}
133
134#if 0
135D4Group *
136
137// I think this was a mistake. jhrg 11/17/16
138#endif
139BaseType *D4Group::ptr_duplicate() { return new D4Group(*this); }
140
142 if (this == &rhs)
143 return *this;
145 m_duplicate(rhs);
146 return *this;
147}
148
155string D4Group::FQN() const {
156 // The root group is named "/" (always)
157 return (name() == "/") ? "/" : static_cast<D4Group *>(get_parent())->FQN() + name() + "/";
158}
159
160D4Group *D4Group::find_child_grp(const string &grp_name) {
161 auto g = find_if(grp_begin(), grp_end(), [grp_name](const D4Group *g) { return g->name() == grp_name; });
162 return (g == grp_end()) ? 0 : *g;
163}
164
165// TODO Add constraint param? jhrg 11/17/13
167 // for each group, starting with the root group
168 // for each variable in the group that is marked to send and is an array
169 // return the btp if it uses the D4Dimension
170 // if it contains child groups, search those
171 // return the btp if it uses the D4Dimension
172 // return null
173
174 // exhaustive breadth-first search for 'dim
175
176 // root group
177 for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i) {
178 if ((*i)->send_p() && (*i)->type() == dods_array_c) {
179 Array *a = static_cast<Array *>(*i);
180 for (Array::Dim_iter di = a->dim_begin(), de = a->dim_end(); di != de; ++di) {
181 if (a->dimension_D4dim(di) == dim)
182 return a;
183 }
184 }
185 }
186
187 for (groupsIter i = grp_begin(), e = grp_end(); i != e; ++i) {
188 BaseType *btp = (*i)->find_first_var_that_uses_dimension(dim);
189 if (btp)
190 return btp;
191 }
192
193 return 0;
194}
195
197 // for each group, starting with the root group
198 // for each variable in the group that is marked to send and is an array
199 // return the btp if it uses the D4EnumDef
200 // if it contains child groups, search those
201 // return the btp if it uses the D4EnumDef
202 // return null
203
204 // exhaustive breadth-first search for 'dim
205
206 // root group
207 for (Vars_iter i = var_begin(), e = var_end(); i != e; ++i) {
208 if ((*i)->send_p() && (*i)->type() == dods_enum_c) {
209 D4Enum *e = static_cast<D4Enum *>(*i);
210 if (e->enumeration() == enum_def)
211 return e;
212 }
213 }
214
215 for (groupsIter i = grp_begin(), e = grp_end(); i != e; ++i) {
216 BaseType *btp = (*i)->find_first_var_that_uses_enumeration(enum_def);
217 if (btp)
218 return btp;
219 }
220
221 return 0;
222}
223
233D4Dimension *D4Group::find_dim(const string &path) {
234 string lpath = path; // get a mutable copy
235
236 // special-case for the root group
237 if (lpath[0] == '/') {
238 if (name() != "/")
239 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
240 else
241 lpath = lpath.substr(1);
242 }
243
244 string::size_type pos = lpath.find('/');
245 if (pos == string::npos) {
246 // name looks like 'bar'
247 return dims()->find_dim(lpath);
248 }
249
250 // name looks like foo/bar/baz where foo and bar must be groups
251 string grp_name = lpath.substr(0, pos);
252 lpath = lpath.substr(pos + 1);
253
254 D4Group *grp = find_child_grp(grp_name);
255 return (grp == 0) ? 0 : grp->find_dim(lpath);
256}
257
263Array *D4Group::find_map_source(const string &path) {
264 BaseType *map_source = m_find_map_source_helper(path);
265
266 // TODO more complete semantic checking jhrg 10/16/13
267 if (map_source && map_source->type() == dods_array_c)
268 return static_cast<Array *>(map_source);
269
270 return 0;
271}
272
278BaseType *D4Group::m_find_map_source_helper(const string &path) {
279 string lpath = path; // get a mutable copy
280
281 // special-case for the root group
282 if (lpath[0] == '/') {
283 if (name() != "/")
284 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
285 else
286 lpath = lpath.substr(1);
287 }
288 string::size_type pos = lpath.find('/');
289 if (pos == string::npos) {
290 // name looks like 'bar'
291 return var(lpath);
292 }
293
294 // name looks like foo/bar/baz where foo and bar must be groups
295 string grp_name = lpath.substr(0, pos);
296
297 D4Group *grp = find_child_grp(grp_name);
298 lpath = lpath.substr(pos + 1);
299
300 // We need to resolve the case that
301 // many group layers are involved such as /foo/bar/bar2/bar3/.../baz
302 // The following code handles this.
303 // KY 2023-05-21
304 //
305 pos = lpath.find('/');
306
307 if (pos == string::npos)
308 return (grp == nullptr) ? nullptr : grp->var(lpath);
309
310 // Recursively check the child groups until we hit the leaf.
311 while (pos != string::npos) {
312
313 grp_name = lpath.substr(0, pos);
314 grp = grp->find_child_grp(grp_name);
315 lpath = lpath.substr(pos + 1);
316 pos = lpath.find('/');
317 }
318
319 return (grp == nullptr) ? nullptr : grp->var(lpath);
320}
321
322D4EnumDef *D4Group::find_enum_def(const string &path) {
323 string lpath = path; // get a mutable copy
324
325 // special-case for the root group
326 if (lpath[0] == '/') {
327 if (name() != "/")
328 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
329 else
330 lpath = lpath.substr(1);
331 }
332
333 string::size_type pos = lpath.find('/');
334 if (pos == string::npos) {
335 // name looks like 'bar'
336 return enum_defs()->find_enum_def(lpath);
337 }
338
339 // name looks like foo/bar/baz where foo and bar must be groups
340 string grp_name = lpath.substr(0, pos);
341 lpath = lpath.substr(pos + 1);
342
343 D4Group *grp = find_child_grp(grp_name);
344 return (grp == 0) ? 0 : grp->enum_defs()->find_enum_def(lpath);
345}
346
354BaseType *D4Group::find_var(const string &path) {
355 string lpath = path; // get a mutable copy
356
357 // special-case for the root group
358 if (lpath[0] == '/') {
359 if (name() != "/")
360 throw InternalErr(__FILE__, __LINE__, "Lookup of a FQN starting in non-root group.");
361 else
362 lpath = lpath.substr(1);
363 }
364
365 string::size_type pos = lpath.find('/');
366 if (pos == string::npos) {
367 // New behavior to accommodate cases where the path ends in a group - the
368 // CE is being used to request all the variables in a Group. So, first check
369 // if this is the name of a Group and if so, return that. Otherwise, look in
370 // the Group's Constructor for a matching variable. jhrg 8/3/22
371 D4Group *grp = find_child_grp(lpath);
372 if (grp != nullptr)
373 return grp;
374 else
375 return var(lpath);
376 }
377
378 // name looks like foo/bar/baz where foo and bar must be groups
379 string grp_name = lpath.substr(0, pos);
380 lpath = lpath.substr(pos + 1);
381
382 D4Group *grp = find_child_grp(grp_name);
383 if (grp == nullptr)
384 return nullptr;
385 else if (lpath.empty())
386 return grp;
387 else
388 return grp->find_var(lpath);
389}
390
399long D4Group::request_size(bool constrained) { return (long)request_size_kb(constrained); }
400
415uint64_t D4Group::request_size_kb(bool constrained) {
416 uint64_t size = 0;
417 // variables
418 for (auto &btp : d_vars) {
419 if (constrained) {
420 if (btp->send_p())
421 size += btp->width_ll(constrained);
422 } else {
423 size += btp->width_ll(constrained);
424 }
425 }
426
427 size = size / 1024; // Make into kilobytes
428
429 // All the child groups
430 for (auto grp : d_groups)
431 size += grp->request_size_kb(constrained);
432
433 return size;
434}
435
436void D4Group::set_read_p(bool state) {
437 groupsIter g = d_groups.begin();
438 while (g != d_groups.end())
439 (*g++)->set_read_p(state);
440
442}
443
444void D4Group::set_send_p(bool state) {
445 groupsIter g = d_groups.begin();
446 while (g != d_groups.end())
447 (*g++)->set_send_p(state);
448
450}
451
452void D4Group::intern_data(/*Crc32 &checksum, DMR &dmr, ConstraintEvaluator &eval*/) {
453 groupsIter g = d_groups.begin();
454 while (g != d_groups.end())
455 (*g++)->intern_data(/*checksum, dmr, eval*/);
456
457 // Specialize how the top-level variables in any Group are sent; include
458 // a checksum for them. A subset operation might make an interior set of
459 // variables, but the parent structure will still be present and the checksum
460 // will be computed for that structure. In other words, DAP4 does not try
461 // to sort out which variables are the 'real' top-level variables and instead
462 // simply computes the CRC for whatever appears as a variable in the root
463 // group.
464 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
465 // Only send the stuff in the current subset.
466 if ((*i)->send_p()) {
467#if 0
468 checksum.Reset();
469#endif
470 (*i)->intern_data(/*checksum, dmr, eval*/);
471#if 0
472 D4Attribute *a = new D4Attribute("DAP4_Checksum_CRC32", attr_str_c);
473
474 ostringstream oss;
475 oss.setf(ios::hex, ios::basefield);
476 oss << setfill('0') << setw(8) << checksum.GetCrc32();
477 a->add_value(oss.str());
478#if INCLUDE_SOURCE_BYTE_ORDER
479 if (um.is_source_big_endian())
480 a->add_value("source:big-endian");
481 else
482 a->add_value("source:little-endian");
483#endif
484 (*i)->attributes()->add_attribute_nocopy(a);
485 DBG(cerr << "CRC32: " << oss.str() << " for " << (*i)->name() << endl);
486#endif
487 }
488 }
489}
490
502void D4Group::serialize(D4StreamMarshaller &m, DMR &dmr, /*ConstraintEvaluator &eval,*/ bool filter) {
503#if 0
504 // This will call Constructor read which will, for everything but a Sequence,
505 // read all of the data in one shot. However, the serialize() methods for the
506 // Arrays, Structures, etc., also have read() calls in them and those can be
507 // used to control how long the data are in memory, e.g., limiting the lifetime
508 // of a large array and avoiding having overlapping arrays when they are not
509 // needed. For a sequence read() has different semantics. It is called once
510 // for every instance and the read_p flag is not used.
511 if (!read_p())
512 read(); // read() throws Error
513#endif
514
515 groupsIter g = d_groups.begin();
516 while (g != d_groups.end())
517 (*g++)->serialize(m, dmr, filter);
518
519 // Specialize how the top-level variables in any Group are sent; include
520 // a checksum for them. A subset operation might make an interior set of
521 // variables, but the parent structure will still be present and the checksum
522 // will be computed for that structure. In other words, DAP4 does not try
523 // to sort out which variables are the 'real' top-level variables and instead
524 // simply computes the CRC for whatever appears as a variable in the root
525 // group.
526 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
527 // Only send the stuff in the current subset.
528 if ((*i)->send_p()) {
529 m.reset_checksum();
530
531 DBG(cerr << "Serializing variable " << (*i)->type_name() << " " << (*i)->name() << endl);
532 (*i)->serialize(m, dmr, filter);
533
534 DBG(cerr << "Wrote CRC32: " << m.get_checksum() << " for " << (*i)->name() << endl);
535 m.put_checksum();
536 }
537 }
538}
539
541 groupsIter g = d_groups.begin();
542 while (g != d_groups.end()) {
543 DBG(cerr << "Deserializing group " << (*g)->name() << endl);
544 (*g++)->deserialize(um, dmr);
545 }
546 // Specialize how the top-level variables in any Group are received; read
547 // their checksum and store the value in a magic attribute of the variable
548 for (Vars_iter i = d_vars.begin(); i != d_vars.end(); i++) {
549 DBG(cerr << "Deserializing variable " << (*i)->type_name() << " " << (*i)->name() << endl);
550 (*i)->deserialize(um, dmr);
551
552 D4Attribute *a = new D4Attribute("DAP4_Checksum_CRC32", attr_str_c);
553 string crc = um.get_checksum_str();
554 a->add_value(crc);
555#if INCLUDE_SOURCE_BYTE_ORDER
556 if (um.is_source_big_endian())
557 a->add_value("source:big-endian");
558 else
559 a->add_value("source:little-endian");
560#endif
561 DBG(cerr << "Read CRC32: " << crc << " for " << (*i)->name() << endl);
562 (*i)->attributes()->add_attribute_nocopy(a);
563 }
564}
565
566void D4Group::print_dap4(XMLWriter &xml, bool constrained) {
567 if (!name().empty() && name() != "/") {
568 // For named groups, if constrained is true only print if this group
569 // has variables that are marked for transmission. For the root group
570 // this test is not made.
571 if (constrained && !send_p())
572 return;
573
574 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)type_name().c_str()) < 0)
575 throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
576
577 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name", (const xmlChar *)name().c_str()) < 0)
578 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
579 }
580
581 // dims
582 if (!dims()->empty())
583 dims()->print_dap4(xml, constrained);
584
585 // enums
586 if (!enum_defs()->empty())
587 enum_defs()->print_dap4(xml, constrained);
588
589 // variables
591 while (v != var_end())
592 (*v++)->print_dap4(xml, constrained);
593
594 // attributes
595 attributes()->print_dap4(xml);
596
597 // groups
598 groupsIter g = d_groups.begin();
599 while (g != d_groups.end())
600 (*g++)->print_dap4(xml, constrained);
601
602 if (!name().empty() && name() != "/") {
603 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
604 throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
605 }
606}
607
608void D4Group::print_decl(FILE *out, string space, bool print_semi, bool constraint_info, bool constrained) {
609 ostringstream oss;
610 print_decl(oss, space, print_semi, constraint_info, constrained);
611 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
612}
613
614void D4Group::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained) {
615 if (constrained && !send_p())
616 return;
617
618 out << space << type_name() << " {\n";
619 for (auto var : d_vars) {
620 var->print_decl(out, space + " ", true, constraint_info, constrained);
621 }
622
623 for (auto grp : d_groups) {
624 grp->print_decl(out, space + " ", true, constraint_info, constrained);
625 }
626
627 out << space << "} " << id2www(name());
628
629 if (constraint_info) { // Used by test drivers only.
630 if (send_p())
631 out << ": Send True";
632 else
633 out << ": Send False";
634 }
635
636 if (print_semi)
637 out << ";\n";
638}
639
640void D4Group::print_val(FILE *out, string space, bool print_decl_p) {
641 ostringstream oss;
642 print_val(oss, space, print_decl_p);
643 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
644}
645
646void D4Group::print_val(ostream &out, string space, bool print_decl_p) {
647 if (print_decl_p) {
648 print_decl(out, space, false);
649 out << " = ";
650 }
651
652 out << "{ ";
653 bool padding_needed = false; // Add padding - which is complex with the two parts. jhrg 8/5/22
654 for (Vars_citer i = d_vars.begin(), e = d_vars.end(); i != e; i++, (void)(i != e && out << ", ")) {
655 (*i)->print_val(out, "", false);
656 padding_needed = true;
657 }
658
659 if (padding_needed)
660 out << " ";
661
662 padding_needed = false;
663 for (auto grp : d_groups) {
664 grp->print_val(out, "", false);
665 padding_needed = true;
666 }
667
668 if (padding_needed)
669 out << " }";
670 else
671 out << "}";
672
673 if (print_decl_p)
674 out << ";\n";
675}
676
677#if 0
694vector<BaseType *> *
695D4Group::transform_to_dap2(AttrTable *parent_attr_table)
696{
697 return transform_to_dap2(parent_attr_table, false);
698}
699#endif
723vector<BaseType *> *D4Group::transform_to_dap2(AttrTable *parent_attr_table) {
724 DBG(cerr << __func__ << "() - BEGIN (" << name() << ")" << endl);
725
726 vector<BaseType *> *results = new vector<BaseType *>(); // LEAK
727
728 // Get the D4Group's attributes
729#if 0
730 AttrTable *group_attrs = attributes()->get_AttrTable(name());
731#else
732 AttrTable *group_attrs = new AttrTable();
733 attributes()->transform_attrs_to_dap2(group_attrs);
734 group_attrs->set_name(name());
735#endif
736
737 // If this is the root group then copy all of its attributes into the parent_attr_table.
738 // The group_attrs AttrTable* above will be replaced by the parent_attr_table.
739 bool is_root = (name() == "/");
740
741 if (is_root) {
742 assert(name() == "/");
743 for (AttrTable::Attr_iter i = group_attrs->attr_begin(), e = group_attrs->attr_end(); i != e; ++i) {
744 if ((*i)->type == Attr_container) {
745 // copy the source container so that the DAS passed in can be
746 // deleted after calling this method.
747 AttrTable *at = new AttrTable(*(*i)->attributes);
748 parent_attr_table->append_container(at, at->get_name());
749 } else {
750 parent_attr_table->append_attr((*i)->name, AttrType_to_String((*i)->type), (*i)->attr,
751 (*i)->is_utf8_str);
752 }
753 }
754 delete group_attrs;
755 group_attrs = parent_attr_table;
756 }
757
758 // Now we process the child variables of this group
759
760 vector<BaseType *> dropped_vars;
761 for (D4Group::Vars_citer i = var_begin(), e = var_end(); i != e; ++i) {
762
763 DBG(cerr << __func__ << "() - Processing member variable '" << (*i)->name()
764 << "' root: " << (is_root ? "true" : "false") << endl);
765
766 vector<BaseType *> *new_vars = (*i)->transform_to_dap2(group_attrs);
767 if (new_vars) { // Might be un-mappable
768 // It's not so game on..
769 for (vector<BaseType *>::iterator vi = new_vars->begin(), ve = new_vars->end(); vi != ve; vi++) {
770 string new_name = (is_root ? "" : FQN()) + (*vi)->name();
771 (*vi)->set_name(new_name);
772 (*vi)->set_parent(NULL);
773 results->push_back((*vi));
774#if 0
775 (*vi) = NULL;
776#endif
777 DBG(cerr << __func__ << "() - Added member variable '" << (*i)->name() << "' "
778 << "to results vector. root: " << (is_root ? "true" : "false") << endl);
779 }
780
781 delete new_vars;
782 } else {
783 DBG(cerr << __func__ << "() - Dropping member variable " << (*i)->name()
784 << " root: " << (is_root ? "true" : "false") << endl);
785 // Got back a NULL, so we are dropping this var.
786 dropped_vars.push_back(*i);
787 }
788 }
789
790 // Process dropped DAP4 vars
791 DBG(cerr << __func__ << "() - Processing " << dropped_vars.size() << " Dropped Variable(s)" << endl);
792
793 AttrTable *dv_attr_table = make_dropped_vars_attr_table(&dropped_vars);
794 if (dv_attr_table) {
795 group_attrs->append_container(dv_attr_table, dv_attr_table->get_name());
796 }
797
798 // Get all the child groups.
799 for (D4Group::groupsIter gi = grp_begin(), ge = grp_end(); gi != ge; ++gi) {
800 vector<BaseType *> *d2_vars = (*gi)->transform_to_dap2(group_attrs);
801 if (d2_vars) {
802 for (vector<BaseType *>::iterator i = d2_vars->begin(), e = d2_vars->end(); i != e; ++i) {
803 results->push_back(*i);
804 }
805 }
806 delete d2_vars;
807 }
808
809 if (!is_root) {
810 group_attrs->set_name(name());
811 parent_attr_table->append_container(group_attrs, group_attrs->get_name());
812 }
813
814 return results;
815}
816
822bool D4Group::is_dap4_projected(std::vector<std::string> &inventory) {
823 bool has_projected_dap4 = false;
824 if (send_p()) {
825 // Groups are a dap4 thing, so if the Group is projected...
826 has_projected_dap4 = true;
827 inventory.emplace_back(type_name() + " " + FQN());
828
829 // Even tho this Group is a projected dap4 variable we still need to
830 // generate an inventory of it's dap4 attributes and projected dap4 child variables
831 // and groups.
832
833 // Inventory the Group's dap4 attributes
834 has_projected_dap4 |= attributes()->has_dap4_types(FQN(), inventory);
835
836 // Process the child variables.
837 for (const auto var : variables()) {
838 has_projected_dap4 |= var->is_dap4_projected(inventory);
839 }
840 // Process the child Groups.
841 for (const auto grp : groups()) {
842 has_projected_dap4 |= grp->is_dap4_projected(inventory);
843 }
844 }
845 return has_projected_dap4;
846}
847
848} /* namespace libdap */
@ attr_str_c
A multidimensional array of identical data types.
Definition Array.h:121
Dim_iter dim_end()
Definition Array.cc:692
std::vector< dimension >::iterator Dim_iter
Definition Array.h:225
virtual D4Dimension * dimension_D4dim(Dim_iter i)
Definition Array.cc:858
Dim_iter dim_begin()
Definition Array.cc:689
Contains the attributes for a dataset.
Definition AttrTable.h:150
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:517
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition AttrTable.cc:247
virtual Attr_iter attr_end()
Definition AttrTable.cc:798
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:308
virtual Attr_iter attr_begin()
Definition AttrTable.cc:793
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:243
std::vector< entry * >::iterator Attr_iter
Definition AttrTable.h:258
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:335
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:296
virtual BaseType * get_parent() const
Definition BaseType.cc:636
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:410
virtual string dataset() const
Returns the name of the dataset used to create this instance.
Definition BaseType.cc:326
virtual D4Attributes * attributes()
Definition BaseType.cc:507
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:478
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:329
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())
std::vector< BaseType * >::const_iterator Vars_citer
Definition Constructor.h:59
void set_read_p(bool state) override
Set the 'read_p' property for the Constructor and its members.
static AttrTable * make_dropped_vars_attr_table(vector< BaseType * > *dropped_vars)
std::vector< BaseType * >::iterator Vars_iter
Definition Constructor.h:60
std::vector< BaseType * > d_vars
Definition Constructor.h:47
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()
Constructor & operator=(const Constructor &rhs)
Definition Constructor.h:70
Constructor(const string &name, const Type &type, bool is_dap4=false)
Definition Constructor.h:52
void add_value(const string &value)
void print_dap4(XMLWriter &xml) const
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
D4Dimension * find_dim(const string &name)
void print_dap4(XMLWriter &xml, bool constrained=false) const
void print_dap4(XMLWriter &xml, bool constrained=false) const
D4EnumDef * find_enum_def(const string &name)
Definition D4EnumDefs.cc:76
Holds a DAP4 enumeration.
Definition D4Enum.h:53
virtual D4EnumDef * enumeration() const
Definition D4Enum.h:112
void print_dap4(XMLWriter &xml, bool constrained=false) override
Definition D4Group.cc:566
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:233
void print_val(FILE *out, string space="", bool print_decl_p=true) override
Prints the value of the variable.
Definition D4Group.cc:640
bool is_dap4_projected(std::vector< std::string > &inventory) override
Definition D4Group.cc:822
D4EnumDef * find_enum_def(const string &path)
Definition D4Group.cc:322
Array * find_map_source(const string &path)
Given a path to an Array that is also a Map, get that Array.
Definition D4Group.cc:263
void add_group_nocopy(D4Group *g)
Definition D4Group.h:123
BaseType * find_var(const string &name)
Definition D4Group.cc:354
groupsIter grp_begin()
Get an iterator to the start of the values.
Definition D4Group.h:116
void intern_data() override
Read data into this variable.
Definition D4Group.cc:452
D4Group * find_child_grp(const string &grp_name)
Definition D4Group.cc:160
void serialize(D4StreamMarshaller &m, DMR &dmr, bool filter=false) override
Serialize a Group.
Definition D4Group.cc:502
BaseType * find_first_var_that_uses_enumeration(D4EnumDef *enum_def)
Definition D4Group.cc:196
uint64_t request_size_kb(bool constrained)
Get the estimated size of a response in kilobytes.
Definition D4Group.cc:415
groupsIter grp_end()
Get an iterator to the end of the values.
Definition D4Group.h:119
D4Dimensions * dims()
Get the dimensions defined for this Group.
Definition D4Group.h:84
void set_send_p(bool state) override
Definition D4Group.cc:444
virtual ~D4Group()
Definition D4Group.cc:125
BaseType * ptr_duplicate() override
Definition D4Group.cc:139
void m_duplicate(const D4Group &g)
Definition D4Group.cc:57
vector< D4Group * >::const_iterator groupsCIter
Definition D4Group.h:69
void set_read_p(bool state) override
Set the 'read_p' property for the Constructor and its members.
Definition D4Group.cc:436
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:614
D4Group & operator=(const D4Group &rhs)
Definition D4Group.cc:141
const vector< D4Group * > & groups() const
Definition D4Group.h:113
D4EnumDefs * enum_defs()
Get the enumerations defined for this Group.
Definition D4Group.h:100
long request_size(bool constrained)
Definition D4Group.cc:399
D4Group(const string &name)
Definition D4Group.cc:104
std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table) override
Transform the D4Group's variables to DAP2 variables.
Definition D4Group.cc:723
std::string FQN() const override
Definition D4Group.cc:155
void deserialize(D4StreamUnMarshaller &um, DMR &dmr) override
Definition D4Group.cc:540
BaseType * find_first_var_that_uses_dimension(D4Dimension *dim)
Definition D4Group.cc:166
vector< D4Group * >::iterator groupsIter
Definition D4Group.h:68
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:61
xmlTextWriterPtr get_writer() const
Definition XMLWriter.h:55
STL iterator class.
#define DBG(x)
Definition debug.h:58
top level DAP object to house generic methods
Definition AISConnect.cc:30
@ dods_group_c
Definition Type.h:122
@ dods_enum_c
Definition Type.h:120
@ dods_array_c
Definition Type.h:107
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:93
@ Attr_container
Definition AttrTable.h:80
string id2www(string in, const string &allowable)
Definition escaping.cc:143