libdap Updated for version 3.21.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
BaseType.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 BaseType.
33//
34// jhrg 9/6/94
35
36#include "config.h"
37
38#include <cstdio> // for stdin and stdout
39
40#include <sstream>
41#include <string>
42
43// #define DODS_DEBUG
44
45#include "Array.h"
46#include "BaseType.h"
47#include "Byte.h"
48#include "Float32.h"
49#include "Float64.h"
50#include "Grid.h"
51#include "Int16.h"
52#include "Int32.h"
53#include "Sequence.h"
54#include "Str.h"
55#include "Structure.h"
56#include "UInt16.h"
57#include "UInt32.h"
58#include "Url.h"
59
60#include "D4Attributes.h"
61#include "D4BaseTypeFactory.h"
62#include "DMR.h"
63#include "XMLWriter.h"
64
65#include "InternalErr.h"
66
67#include "DapIndent.h"
68#include "escaping.h"
69#include "util.h"
70
71#include "debug.h"
72
73using namespace std;
74
75namespace libdap {
76
77// Protected copy mfunc
78
85void BaseType::m_duplicate(const BaseType &bt) {
86 DBG(cerr << "In BaseType::m_duplicate for " << bt.name() << endl);
87
88 d_name = bt.d_name;
89 d_type = bt.d_type;
90 d_dataset = bt.d_dataset;
91 d_is_read = bt.d_is_read; // added, reza
92 d_is_send = bt.d_is_send; // added, reza
93 d_in_selection = bt.d_in_selection;
94 d_is_synthesized = bt.d_is_synthesized; // 5/11/2001 jhrg
95
96 d_parent = bt.d_parent; // copy pointers 6/4/2001 jhrg
97
98 d_attr = bt.d_attr; // Deep copy.
99
100 if (bt.d_attributes)
101 d_attributes = new D4Attributes(*bt.d_attributes); // deep copy
102 else
103 d_attributes = 0; // init to null if not used.
104
105 d_is_dap4 = bt.d_is_dap4;
106
107 DBG(cerr << "Exiting BaseType::m_duplicate for " << bt.name() << endl);
108}
109
110// Public mfuncs
111
124BaseType::BaseType(const string &n, const Type &t, bool is_dap4)
125 : d_name(n), d_type(t), d_dataset(""), d_is_read(false), d_is_send(false), d_parent(0), d_attributes(0),
126 d_is_dap4(is_dap4), d_in_selection(false), d_is_synthesized(false) {}
127
140BaseType::BaseType(const string &n, const string &d, const Type &t, bool is_dap4)
141 : d_name(n), d_type(t), d_dataset(d), d_is_read(false), d_is_send(false), d_parent(0), d_attributes(0),
142 d_is_dap4(is_dap4), d_in_selection(false), d_is_synthesized(false) {}
143
145BaseType::BaseType(const BaseType &copy_from) : DapObj() {
146 DBG(cerr << "In BaseTpe::copy_ctor for " << copy_from.name() << endl);
147 m_duplicate(copy_from);
148}
149
150BaseType::~BaseType() {
151 DBG2(cerr << "Entering ~BaseType (" << this << ")" << endl);
152
153 if (d_attributes)
154 delete d_attributes;
155
156 DBG2(cerr << "Exiting ~BaseType" << endl);
157}
158
159BaseType &BaseType::operator=(const BaseType &rhs) {
160 if (this == &rhs)
161 return *this;
162 m_duplicate(rhs);
163 return *this;
164}
165
170string BaseType::toString() {
171 ostringstream oss;
172 oss << "BaseType (" << this << "):" << endl
173 << " _name: " << name() << endl
174 << " _type: " << type_name() << endl
175 << " _dataset: " << d_dataset << endl
176 << " _read_p: " << d_is_read << endl
177 << " _send_p: " << d_is_send << endl
178 << " _synthesized_p: " << d_is_synthesized << endl
179 << " d_parent: " << d_parent << endl
180 << " d_attr: " << hex << &d_attr << dec << endl;
181
182 return oss.str();
183}
184
200void BaseType::transform_to_dap4(D4Group * /*root*/, Constructor *container) {
201 BaseType *dest = ptr_duplicate();
202 // If it's already a DAP4 object then we can just return it!
203 if (!is_dap4()) {
204 dest->attributes()->transform_to_dap4(get_attr_table());
205 dest->set_is_dap4(true);
206 }
207 container->add_var_nocopy(dest);
208}
209
240std::vector<BaseType *> *BaseType::transform_to_dap2(AttrTable *) {
241 BaseType *dest = this->ptr_duplicate();
242 // convert the d4 attributes to a dap2 attribute table.
243 // HK-403. jhrg 6/17/19
244#if 0
245 AttrTable *attrs = this->attributes()->get_AttrTable(name());
246 dest->set_attr_table(*attrs);
247#else
248 if (dest->get_attr_table().get_size() == 0) {
249 attributes()->transform_attrs_to_dap2(&dest->get_attr_table());
250 dest->get_attr_table().set_name(name());
251 }
252#endif
253
254 dest->set_is_dap4(false);
255
256 vector<BaseType *> *result = new vector<BaseType *>();
257 result->push_back(dest);
258 return result;
259}
260
269void BaseType::dump(ostream &strm) const {
270 strm << DapIndent::LMarg << "BaseType::dump - (" << (void *)this << ")" << endl;
271 DapIndent::Indent();
272
273 strm << DapIndent::LMarg << "name: " << name() << endl;
274 strm << DapIndent::LMarg << "type: " << type_name() << endl;
275 strm << DapIndent::LMarg << "dataset: " << d_dataset << endl;
276 strm << DapIndent::LMarg << "read_p: " << d_is_read << endl;
277 strm << DapIndent::LMarg << "send_p: " << d_is_send << endl;
278 strm << DapIndent::LMarg << "synthesized_p: " << d_is_synthesized << endl;
279 strm << DapIndent::LMarg << "d_is_dap4: " << d_is_dap4 << endl;
280 strm << DapIndent::LMarg << "parent: " << (void *)d_parent << endl;
281 strm << DapIndent::LMarg << "attributes: " << endl;
282 DapIndent::Indent();
283
284 if (d_attributes)
285 d_attributes->dump(strm);
286 else
287 d_attr.dump(strm);
288
289 DapIndent::UnIndent();
290
291 DapIndent::UnIndent();
292}
293
296string BaseType::name() const { return d_name; }
297
304string BaseType::FQN() const {
305 if (get_parent() == 0)
306 return name();
307 else if (get_parent()->type() == dods_group_c)
308 return get_parent()->FQN() + name();
309 else
310 return get_parent()->FQN() + "." + name();
311}
312
314void BaseType::set_name(const string &n) {
315 string name = n;
316 d_name = www2id(name); // www2id writes into its param.
317}
318
326string BaseType::dataset() const { return d_dataset; }
327
329Type BaseType::type() const { return d_type; }
330
332void BaseType::set_type(const Type &t) { d_type = t; }
333
335string BaseType::type_name() const {
336 if (is_dap4())
337 return libdap::D4type_name(d_type);
338 else
339 return libdap::D2type_name(d_type);
340}
341
347bool BaseType::is_simple_type() const { return libdap::is_simple_type(type()); }
348
352bool BaseType::is_vector_type() const { return libdap::is_vector_type(type()); }
353
358bool BaseType::is_constructor_type() const { return libdap::is_constructor_type(type()); }
359
385int BaseType::element_count(bool) { return 1; }
386
390bool BaseType::synthesized_p() { return d_is_synthesized; }
391
397void BaseType::set_synthesized_p(bool state) { d_is_synthesized = state; }
398
399// Return the state of d_is_read (true if the value of the variable has been
400// read (and is in memory) false otherwise).
401
410bool BaseType::read_p() { return d_is_read; }
411
442void BaseType::set_read_p(bool state) {
443 // The this comment is/was wrong!
444 // The is_synthesized property was not being used and the more I thought
445 // about how this was coded, the more this code below seemed like a bad idea.
446 // Once the property was set, the read_p property could not be changed.
447 // That seems a little silly. Also, I think I need to use this is_synthesized
448 // property for some of the server function code I'm working on for Raytheon,
449 // and I'd like to be able to control the read_p property! jhrg 3/9/15
450
451 // What's true: The is_synthesized property is used by
452 // 'projection functions' in the freeform handler. It might be better
453 // to modify the FFtypes to support this behavior, but for now I'm returning
454 // the library to its old behavior. That this change (setting is_read
455 // of the value of is_syn...) broke the FF handler was not detected
456 // because the FF tests were not being run due to an error in the FF
457 // bes-testsuite Makefile.am). jhrg 9/9/15
458
459#if 1
460 if (!d_is_synthesized) {
461 d_is_read = state;
462 }
463#else
464 d_is_read = state;
465#endif
466}
467
478bool BaseType::send_p() { return d_is_send; }
479
488void BaseType::set_send_p(bool state) {
489 DBG2(cerr << "Calling BaseType::set_send_p() for: " << this->name() << endl);
490 d_is_send = state;
491}
492
498AttrTable &BaseType::get_attr_table() { return d_attr; }
499
502void BaseType::set_attr_table(const AttrTable &at) { d_attr = at; }
503
507D4Attributes *BaseType::attributes() {
508 if (!d_attributes)
509 d_attributes = new D4Attributes();
510 return d_attributes;
511}
512
513void BaseType::set_attributes(D4Attributes *attrs) { d_attributes = new D4Attributes(*attrs); }
514
515void BaseType::set_attributes_nocopy(D4Attributes *attrs) { d_attributes = attrs; }
517
544void BaseType::transfer_attributes(AttrTable *at_container) {
545
546 DBG(cerr << __func__ << "() - BEGIN name:'" << name() << "'" << endl);
547
548 AttrTable *at = at_container->get_attr_table(name());
549 DBG(cerr << __func__ << "() - at: " << (void *)at << endl);
550
551 if (at) {
552 at->set_is_global_attribute(false);
553 DBG(cerr << __func__ << "() - Processing AttrTable: " << at->get_name() << endl);
554
555 AttrTable::Attr_iter at_p = at->attr_begin();
556 while (at_p != at->attr_end()) {
557 DBG(cerr << __func__ << "() - Attribute '" << at->get_name(at_p) << "' is type: " << at->get_type(at_p)
558 << endl);
559 if (at->get_attr_type(at_p) == Attr_container) {
560 // An attribute container may actually represent a child member variable. When
561 // that's the case we don't want to add the container to the parent type, but
562 // rather let any child of BaseType deal with those containers in the child's
563 // overridden transfer_attributes() method.
564 // We capitalize on the magic of the BaseType API and utilize the var() method
565 // to check for a child variable of the same name and, if one exists, we'll skip
566 // this AttrTable and let a child constructor class like Grid or Constructor
567 // deal with it.
568 BaseType *bt = var(at->get_name(at_p), true);
569 if (bt == 0) {
570 DBG(cerr << __func__ << "() - Adding container '" << at->get_name(at_p) << endl);
571 get_attr_table().append_container(new AttrTable(*at->get_attr_table(at_p)), at->get_name(at_p));
572 } else {
573 DBG(cerr << __func__ << "() - Found child var: '" << bt->type_name() << " " << bt->name()
574 << " (address:" << (void *)bt << ")" << endl);
575 DBG(cerr << __func__ << "() - Skipping container '" << at->get_name(at_p) << endl);
576 }
577 } else {
578 DBG(cerr << __func__ << "() - Adding Attribute '" << at->get_name(at_p) << endl);
579 get_attr_table().append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p),
580 (*at_p)->is_utf8_str);
581 }
582 at_p++;
583 }
584 } else {
585 DBG(cerr << __func__ << "() - Unable to locate AttrTable '" << name() << "' SKIPPING" << endl);
586 }
587}
588
600bool BaseType::is_in_selection() { return d_in_selection; }
601
611void BaseType::set_in_selection(bool state) { d_in_selection = state; }
612
613// Protected method.
622void BaseType::set_parent(BaseType *parent) {
623 if (!dynamic_cast<Constructor *>(parent) && !dynamic_cast<Vector *>(parent) && parent != 0)
624 throw InternalErr("Call to set_parent with incorrect variable type.");
625
626 d_parent = parent;
627}
628
629// Public method.
630
636BaseType *BaseType::get_parent() const { return d_parent; }
637
638BaseType *BaseType::get_ancestor() {
639 if (d_parent)
640 return d_parent->get_ancestor();
641 else
642 return this;
643}
644
645// Documented in the header file.
646BaseType *BaseType::var(const string & /*name*/, bool /*exact_match*/, btp_stack * /*s*/) {
647 return static_cast<BaseType *>(0);
648}
649
666BaseType *BaseType::var(const string &, btp_stack &) { return static_cast<BaseType *>(0); }
667
697void BaseType::add_var(BaseType *, Part) { throw InternalErr(__FILE__, __LINE__, "BaseType::add_var unimplemented"); }
698
699void BaseType::add_var_nocopy(BaseType *, Part) {
700 throw InternalErr(__FILE__, __LINE__, "BaseType::add_var_nocopy unimplemented");
701}
702
775bool BaseType::read() {
776 if (d_is_read)
777 return true;
778
779 throw InternalErr("Unimplemented BaseType::read() method called for the variable named: " + name());
780}
781
782void BaseType::intern_data(ConstraintEvaluator &, DDS & /*dds*/) {
783#if USE_LOCAL_TIMEOUT_SCHEME
784 dds.timeout_on();
785#endif
786 if (is_dap4())
787 throw Error(string("A method usable only with DAP2 variables was called on a DAP4 variable (")
788 .append(name())
789 .append(")."),
790 __FILE__, __LINE__);
791
792 DBG2(cerr << "BaseType::intern_data: " << name() << endl);
793 if (!read_p())
794 read(); // read() throws Error and InternalErr
795#if USE_LOCAL_TIMEOUT_SCHEME
796 dds.timeout_off();
797#endif
798}
799
805void BaseType::intern_data() {
806 if (!read_p())
807 read(); // read() throws Error and InternalErr
808}
809
810bool BaseType::serialize(ConstraintEvaluator &, DDS &, Marshaller &, bool) {
811 throw InternalErr(__FILE__, __LINE__, "The DAP2 serialize() method has not been implemented for " + type_name());
812}
813
814bool BaseType::deserialize(UnMarshaller &, DDS *, bool) {
815 throw InternalErr(__FILE__, __LINE__, "The DAP2 deserialize() method has not been implemented for " + type_name());
816}
817
818void BaseType::serialize(D4StreamMarshaller &, DMR &, /*ConstraintEvaluator &,*/ bool) {
819 throw InternalErr(__FILE__, __LINE__, "The DAP4 serialize() method has not been implemented for " + type_name());
820}
821
822void BaseType::deserialize(D4StreamUnMarshaller &, DMR &) {
823 throw InternalErr(__FILE__, __LINE__, "The DAP4 deserialize() method has not been implemented for " + type_name());
824}
825
868void BaseType::print_decl(FILE *out, string space, bool print_semi, bool constraint_info, bool constrained) {
869 ostringstream oss;
870 print_decl(oss, space, print_semi, constraint_info, constrained);
871 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
872}
873
916void BaseType::print_decl(ostream &out, string space, bool print_semi, bool constraint_info, bool constrained) {
917 // if printing the constrained declaration, exit if this variable was not
918 // selected.
919 if (constrained && !send_p())
920 return;
921
922 out << space << type_name() << " " << id2www(name());
923
924 if (constraint_info) {
925 if (send_p())
926 out << ": Send True";
927 else
928 out << ": Send False";
929 }
930
931 if (print_semi)
932 out << ";\n";
933}
934
949void BaseType::print_val(FILE *out, string space, bool print_decl_p) {
950 ostringstream oss;
951 print_val(oss, space, print_decl_p);
952 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
953}
954
962void BaseType::print_xml(FILE *out, string space, bool constrained) {
963 XMLWriter xml(space);
964 print_xml_writer(xml, constrained);
965 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
966}
967
975void BaseType::print_xml(ostream &out, string space, bool constrained) {
976 XMLWriter xml(space);
977 print_xml_writer(xml, constrained);
978 out << xml.get_doc();
979}
980
987void BaseType::print_xml_writer(XMLWriter &xml, bool constrained) {
988 if (constrained && !send_p())
989 return;
990
991 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)type_name().c_str()) < 0)
992 throw InternalErr(__FILE__, __LINE__, "Could not write " + type_name() + " element");
993
994 if (!name().empty())
995 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name", (const xmlChar *)name().c_str()) < 0)
996 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
997
998 if (is_dap4())
999 attributes()->print_dap4(xml);
1000
1001 if (!is_dap4() && get_attr_table().get_size() > 0)
1002 get_attr_table().print_xml_writer(xml);
1003
1004 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1005 throw InternalErr(__FILE__, __LINE__, "Could not end " + type_name() + " element");
1006}
1007
1015void BaseType::print_dap4(XMLWriter &xml, bool constrained) { print_xml_writer(xml, constrained); }
1016
1017// Compares the object's current state with the semantics of a particular
1018// type. This will typically be defined in ctor classes (which have
1019// complicated semantics). For BaseType, an object is semantically correct if
1020// it has both a non-null name and type.
1021//
1022// NB: This is not the same as an invariant -- during the parse objects exist
1023// but have no name. Also, the bool ALL defaults to false for BaseType. It is
1024// used by children of CtorType.
1025//
1026// Returns: true if the object is semantically correct, false otherwise.
1027
1056bool BaseType::check_semantics(string &msg, bool) {
1057 bool sem = (d_type != dods_null_c && name().length());
1058
1059 if (!sem)
1060 msg = "Every variable must have both a name and a type\n";
1061
1062 return sem;
1063}
1064
1101bool BaseType::ops(BaseType *, int) {
1102 // Even though ops is a public method, it can never be called because
1103 // they will never have a BaseType object since this class is abstract,
1104 // however any of the child classes could by mistake call BaseType::ops
1105 // so this is an internal error. Jose Garcia
1106 throw InternalErr(__FILE__, __LINE__, "Unimplemented operator.");
1107}
1108
1125bool BaseType::d4_ops(BaseType *, int) { throw InternalErr(__FILE__, __LINE__, "Unimplemented operator."); }
1126
1138unsigned int BaseType::width(bool /* constrained */) const { throw InternalErr(__FILE__, __LINE__, "not implemented"); }
1139
1140int64_t BaseType::width_ll(bool /* constrained */) const { throw InternalErr(__FILE__, __LINE__, "not implemented"); }
1141
1148bool BaseType::is_dap4_projected(std::vector<string> &inventory) {
1149 bool has_projected_dap4 = false;
1150 if (send_p()) {
1151 has_projected_dap4 = attributes()->has_dap4_types(FQN(), inventory);
1152 }
1153 return has_projected_dap4;
1154}
1155
1156} // namespace libdap
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 unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:308
void print_xml_writer(XMLWriter &xml)
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
top level DAP object to house generic methods
Definition AISConnect.cc:30
virtual BaseType * ptr_duplicate()=0
Type
Identifies the data type.
Definition Type.h:94
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition BaseType.cc:347
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:410
virtual string type_name() const
Returns the type of the class instance as a string.
Definition BaseType.cc:335
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr)
Returns a pointer to a member of a constructor class.
string www2id(const string &in, const string &escape, const string &except)
Definition escaping.cc:202
virtual bool send_p()
Should this variable be sent?
Definition BaseType.cc:478
string D2type_name(Type t)
Returns the type of the class instance as a string. Supports all DAP2 types and not the DAP4-only typ...
Definition util.cc:644
string D4type_name(Type t)
Returns the type of the class instance as a string. Supports all DAP4 types and not the DAP2-only typ...
Definition util.cc:688
virtual void print_val(FILE *out, string space="", bool print_decl_p=true)
Prints the value of the variable.
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable.
Definition BaseType.cc:358
virtual bool is_vector_type() const
Returns true if the instance is a vector (i.e., array) type variable.
Definition BaseType.cc:352
string id2www(string in, const string &allowable)
Definition escaping.cc:143