libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4Attributes.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#include "config.h"
26
27#include <algorithm>
28
29#include "D4AttributeType.h"
30#include "D4Attributes.h"
31#include "InternalErr.h"
32
33#include "AttrTable.h"
34
35#include "DapIndent.h"
36#include "debug.h"
37#include "escaping.h"
38#include "util.h"
39
40namespace libdap {
41
45string D4AttributeTypeToString(D4AttributeType at) {
46 switch (at) {
47 case attr_null_c:
48 return "null";
49
50 case attr_byte_c:
51 return "Byte";
52
53 case attr_int16_c:
54 return "Int16";
55
56 case attr_uint16_c:
57 return "UInt16";
58
59 case attr_int32_c:
60 return "Int32";
61
62 case attr_uint32_c:
63 return "UInt32";
64
65 case attr_float32_c:
66 return "Float32";
67
68 case attr_float64_c:
69 return "Float64";
70
71 case attr_str_c:
72 return "String";
73
74 case attr_url_c:
75 return "Url";
76
77 // Added for DAP4
78 case attr_int8_c:
79 return "Int8";
80
81 case attr_uint8_c:
82 return "UInt8";
83
84 case attr_int64_c:
85 return "Int64";
86
87 case attr_uint64_c:
88 return "UInt64";
89
90 case attr_enum_c:
91 return "Enum";
92
93 case attr_opaque_c:
94 return "Opaque";
95
96 // These are specific to attributes while the other types are
97 // also supported by the variables. jhrg 4/17/13
99 return "Container";
100
101 case attr_otherxml_c:
102 return "OtherXML";
103
104 default:
105 throw InternalErr(__FILE__, __LINE__, "Unsupported attribute type");
106 }
107}
108
109D4AttributeType StringToD4AttributeType(string s) {
110 downcase(s);
111
112 if (s == "container")
113 return attr_container_c;
114
115 else if (s == "byte")
116 return attr_byte_c;
117 else if (s == "int8")
118 return attr_int8_c;
119 else if (s == "uint8")
120 return attr_uint8_c;
121 else if (s == "int16")
122 return attr_int16_c;
123 else if (s == "uint16")
124 return attr_uint16_c;
125 else if (s == "int32")
126 return attr_int32_c;
127 else if (s == "uint32")
128 return attr_uint32_c;
129 else if (s == "int64")
130 return attr_int64_c;
131 else if (s == "uint64")
132 return attr_uint64_c;
133
134 else if (s == "float32")
135 return attr_float32_c;
136 else if (s == "float64")
137 return attr_float64_c;
138
139 else if (s == "string")
140 return attr_str_c;
141 else if (s == "url")
142 return attr_url_c;
143 else if (s == "otherxml")
144 return attr_otherxml_c;
145 else
146 return attr_null_c;
147}
148
149void D4Attribute::m_duplicate(const D4Attribute &src) {
150 d_name = src.d_name;
151 d_type = src.d_type;
152 d_values = src.d_values;
153 if (src.d_attributes)
154 d_attributes = new D4Attributes(*src.d_attributes);
155 else
156 d_attributes = 0;
157}
158
159D4Attribute::D4Attribute(const D4Attribute &src) { m_duplicate(src); }
160
161D4Attribute::~D4Attribute() { delete d_attributes; }
162
164 if (this == &rhs)
165 return *this;
166 m_duplicate(rhs);
167 return *this;
168}
169
171 if (!d_attributes)
172 d_attributes = new D4Attributes();
173 return d_attributes;
174}
175
185 // for every attribute in at, copy it to this.
186 for (AttrTable::Attr_iter i = at.attr_begin(), e = at.attr_end(); i != e; ++i) {
187 string name = at.get_name(i);
188 AttrType type = at.get_attr_type(i);
189
190 switch (type) {
191 case Attr_container: {
193 D4Attributes *attributes = a->attributes(); // allocates a new object
194 attributes->transform_to_dap4(*at.get_attr_table(i));
196 break;
197 }
198 case Attr_byte: {
199 D4Attribute *a = new D4Attribute(name, attr_byte_c);
202 break;
203 }
204 case Attr_int16: {
205 D4Attribute *a = new D4Attribute(name, attr_int16_c);
208 break;
209 }
210 case Attr_uint16: {
211 D4Attribute *a = new D4Attribute(name, attr_uint16_c);
214 break;
215 }
216 case Attr_int32: {
217 D4Attribute *a = new D4Attribute(name, attr_int32_c);
220 break;
221 }
222 case Attr_uint32: {
223 D4Attribute *a = new D4Attribute(name, attr_uint32_c);
226 break;
227 }
228 case Attr_float32: {
229 D4Attribute *a = new D4Attribute(name, attr_float32_c);
232 break;
233 }
234 case Attr_float64: {
235 D4Attribute *a = new D4Attribute(name, attr_float64_c);
238 break;
239 }
240 case Attr_string: {
241 D4Attribute *a = new D4Attribute(name, attr_str_c);
242 a->set_utf8_str_flag((*i)->is_utf8_str);
245 break;
246 }
247 case Attr_url: {
248 D4Attribute *a = new D4Attribute(name, attr_url_c);
251 break;
252 }
253 case Attr_other_xml: {
257 break;
258 }
259 default:
260 throw InternalErr(__FILE__, __LINE__, "Unknown DAP2 attribute type in D4Attributes::copy_from_dap2()");
261 }
262 }
263}
264
265AttrType get_dap2_AttrType(D4AttributeType d4_type) {
266 switch (d4_type) {
267 // These types are common between DAP4 and DAP2.
268 case attr_container_c: {
269 return Attr_container;
270 }
271 case attr_byte_c: {
272 return Attr_byte;
273 }
274 case attr_int16_c: {
275 return Attr_int16;
276 }
277 case attr_uint16_c: {
278 return Attr_uint16;
279 }
280 case attr_int32_c: {
281 return Attr_int32;
282 }
283 case attr_uint32_c: {
284 return Attr_uint32;
285 }
286 case attr_float32_c: {
287 return Attr_float32;
288 }
289 case attr_float64_c: {
290 return Attr_float64;
291 }
292 case attr_str_c: {
293 return Attr_string;
294 }
295 case attr_url_c: {
296 return Attr_url;
297 }
298 case attr_otherxml_c: {
299 return Attr_other_xml;
300 }
301 case attr_uint8_c: {
302 return Attr_byte;
303 }
304
305 // Types exclusive to DAP4
306 case attr_int8_c: {
307 return Attr_int8;
308 }
309 case attr_int64_c: {
310 return Attr_int64;
311 }
312 case attr_uint64_c: {
313 return Attr_uint64;
314 }
315 case attr_enum_c: {
316 return Attr_enum;
317 }
318 case attr_opaque_c: {
319 return Attr_opaque;
320 }
321 default:
322 throw InternalErr(__FILE__, __LINE__, "Unknown DAP4 attribute.");
323 }
324}
325
332 // for every attribute in d4_attrs, copy it to d2_attr_table.
333 for (D4Attributes::D4AttributesIter i = attribute_begin(), e = attribute_end(); i != e; ++i) {
334 string name = (*i)->name();
335 D4AttributeType d4_attr_type = (*i)->type();
336 AttrType d2_attr_type = get_dap2_AttrType(d4_attr_type);
337 string d2_attr_type_name = AttrType_to_String(d2_attr_type);
338
339 switch (d4_attr_type) {
340 case attr_container_c: {
341 AttrTable *child_attr_table = new AttrTable();
342 child_attr_table->set_name(name);
343
344 (*i)->attributes()->transform_attrs_to_dap2(child_attr_table);
345 d2_attr_table->append_container(child_attr_table, name);
346 break;
347 }
348 default: {
349 for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
350 d2_attr_table->append_attr(name, d2_attr_type_name, *vi, (*i)->get_utf8_str_flag());
351 }
352
353 break;
354 }
355 }
356 }
357}
358
359#if 0
369void D4Attributes::load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
370{
371 // for every attribute in d4_attrs, copy it to d2_attr_table.
372 for (D4Attributes::D4AttributesIter i = d4_attrs->attribute_begin(), e = d4_attrs->attribute_end(); i != e; ++i) {
373 string name = (*i)->name();
374 D4AttributeType d4_attr_type = (*i)->type();
375 string d2_attr_type_name = AttrType_to_String(get_dap2_AttrType(d4_attr_type));
376
377#if 0
378 D4Attribute::D4AttributeIter vitr = (*i)->value_begin();
379 D4Attribute::D4AttributeIter end = (*i)->value_end();
380
381 vector<string> values;
382 for (; vitr != end; vitr++) {
383 values.push_back((*vitr));
384 }
385#endif
386
387 switch (d4_attr_type) {
388 case attr_container_c: {
389 // Attr_container
390 AttrTable *child_attr_table = new AttrTable();
391 child_attr_table->set_name(name);
392
393 load_AttrTable(child_attr_table, (*i)->attributes());
394 d2_attr_table->append_container(child_attr_table, name);
395 break;
396 }
397 default: {
398 for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
399 d2_attr_table->append_attr(name, d2_attr_type_name, *vi);
400 }
401
402 break;
403 }
404 }
405 }
406}
407
408
416AttrTable *D4Attributes::get_AttrTable(const string name)
417{
418 AttrTable *at = new AttrTable();
420#if 0
421 load_AttrTable(at, this);
422#endif
423 at->set_name(name);
424 return at;
425}
426#endif
427
428D4Attribute *D4Attributes::find_depth_first(const string &name, D4AttributesIter i) {
429 if (i == attribute_end())
430 return 0;
431 else if ((*i)->name() == name)
432 return *i;
433 else if ((*i)->type() == attr_container_c)
434 return find_depth_first(name, (*i)->attributes()->attribute_begin());
435 else
436 return find_depth_first(name, ++i);
437}
438
439D4Attribute *D4Attributes::find(const string &name) { return find_depth_first(name, attribute_begin()); }
440
444D4Attribute *D4Attributes::get(const string &fqn) {
445 // name1.name2.name3
446 // name1
447 // name1.name2
448 size_t pos = fqn.find('.');
449 string part = fqn.substr(0, pos);
450 string rest = "";
451
452 if (pos != string::npos)
453 rest = fqn.substr(pos + 1);
454
455 DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
456
457 if (!part.empty()) {
458 if (!rest.empty()) {
460 while (i != attribute_end()) {
461 if ((*i)->name() == part && (*i)->type() == attr_container_c)
462 return (*i)->attributes()->get(rest);
463 ++i;
464 }
465 } else {
467 while (i != attribute_end()) {
468 if ((*i)->name() == part)
469 return (*i);
470 ++i;
471 }
472 }
473 }
474
475 return 0;
476}
477
486void D4Attributes::erase_named_attribute(const string &name) {
487 for (auto &attr : d_attrs) {
488 if (attr->name() == name) {
489 delete attr;
490 attr = nullptr;
491 }
492 }
493 d_attrs.erase(remove(d_attrs.begin(), d_attrs.end(), nullptr), d_attrs.end());
494}
495
500void D4Attributes::erase(const string &fqn) {
501 // name1.name2.name3; part is name1 and rest is name2.name3
502 // name1; part is name1 and rest is ""
503 // name1.name2; part is name1 and rest is name2
504 size_t pos = fqn.find('.');
505 string part = fqn.substr(0, pos);
506 string rest = "";
507
508 if (pos != string::npos)
509 rest = fqn.substr(pos + 1);
510
511 if (!part.empty()) {
512 if (!rest.empty()) {
513 // in this case, we are not looking for a leaf node, so descend the
514 // attribute container hierarchy.
515 for (auto &a : d_attrs) {
516 if (a->name() == part && a->type() == attr_container_c) {
517 a->attributes()->erase(rest);
518 }
519 }
520 } else {
522 }
523 }
524}
525
527 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Attribute") < 0)
528 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
529 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name", (const xmlChar *)name().c_str()) < 0)
530 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
531 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"type",
532 (const xmlChar *)D4AttributeTypeToString(type()).c_str()) < 0)
533 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
534
535 switch (type()) {
536 case attr_container_c:
537 // Just print xml when containing attributes. KY 2021-03-12
538 if (d_attributes)
539 d_attributes->print_dap4(xml);
540 break;
541
542 case attr_otherxml_c:
543 if (num_values() != 1)
544 throw Error("OtherXML attributes cannot be vector-valued.");
545 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar *)value(0).c_str()) < 0)
546 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
547 break;
548
549 case attr_url_c:
550 case attr_str_c: {
551
552 // Need to escape special characters that xml doesn't allow. Note: the XML escaping is
553 // not the same as the das string escaping. See escattr_xml in the escaping.cc for details.
554 // KY 08-22-22
555#if 0
556 D4AttributeCIter i = d_values.begin();//value_begin();
557#endif
558 auto i = d_values.begin();
559 while (i != d_values.end()) {
560 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Value") < 0)
561 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
562#if 0
563 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
564#endif
565 string s = (get_utf8_str_flag()) ? (*i++) : escattr_xml(*i++);
566 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar *)s.c_str()) < 0)
567 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
568
569 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
570 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
571 }
572 break;
573 }
574
575 default: {
576 // Assume only valid types make it into instances
577 D4AttributeCIter i = d_values.begin(); // value_begin();
578 while (i != d_values.end()) {
579 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Value") < 0)
580 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
581
582 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar *)(*i++).c_str()) < 0)
583 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
584
585 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
586 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
587 }
588
589 break;
590 }
591 }
592
593 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
594 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
595}
596
605void D4Attribute::dump(ostream &strm) const {
606 strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
607
609
610 XMLWriter xml;
611 print_dap4(xml);
612 strm << DapIndent::LMarg << xml.get_doc() << flush;
613
615}
616
618 if (empty())
619 return;
620
621 D4AttributesCIter i = d_attrs.begin();
622 while (i != d_attrs.end()) {
623 (*i++)->print_dap4(xml);
624 }
625}
626
633bool D4Attribute::is_dap4_type(const std::string &path, std::vector<std::string> &inventory) {
634 bool ima_d4_attr = false;
635 switch (type()) {
636 case attr_int8_c:
637 case attr_int64_c:
638 case attr_uint64_c:
639 ima_d4_attr = true;
640 break;
641 case attr_container_c:
642 ima_d4_attr = attributes()->has_dap4_types(path, inventory);
643 break;
644 default:
645 break;
646 }
647 return ima_d4_attr;
648}
649
656bool D4Attributes::has_dap4_types(const std::string &path, std::vector<std::string> &inventory) const {
657 bool has_d4_attr = false;
658 for (const auto attr : attributes()) {
659 string attr_fqn = path + "@" + attr->name();
660 bool isa_d4_attr = attr->is_dap4_type(attr_fqn, inventory);
661 if (isa_d4_attr) {
662 inventory.emplace_back(D4AttributeTypeToString(attr->type()) + " " + attr_fqn);
663 }
664 has_d4_attr |= isa_d4_attr;
665 }
666 return has_d4_attr;
667}
668
677void D4Attributes::dump(ostream &strm) const {
678 strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
679
681
682 XMLWriter xml;
683 print_dap4(xml);
684 strm << DapIndent::LMarg << xml.get_doc() << flush;
685
687}
688
689} // namespace libdap
@ attr_container_c
@ attr_int16_c
@ attr_enum_c
@ attr_uint64_c
@ attr_url_c
@ attr_float64_c
@ attr_opaque_c
@ attr_float32_c
@ attr_otherxml_c
@ attr_byte_c
@ attr_int8_c
@ attr_int64_c
@ attr_int32_c
@ attr_str_c
@ attr_null_c
@ attr_uint16_c
@ attr_uint8_c
@ attr_uint32_c
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 AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:699
virtual Attr_iter attr_end()
Definition AttrTable.cc:798
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:738
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
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition AttrTable.cc:709
D4Attributes * attributes()
bool is_dap4_type(const std::string &path, std::vector< std::string > &inventory)
void add_value_vector(const vector< string > &values)
void print_dap4(XMLWriter &xml) const
vector< string >::const_iterator D4AttributeCIter
D4Attribute & operator=(const D4Attribute &rhs)
unsigned int num_values() const
bool get_utf8_str_flag() const
string value(unsigned int i) const
vector< string >::iterator D4AttributeIter
void set_utf8_str_flag(bool utf8_str_flag)
virtual void dump(ostream &strm) const
dumps information about this object
D4AttributeType type() const
string name() const
void erase(const string &fqn)
Erase the given attribute.
D4Attribute * find(const string &name)
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
D4Attribute * get(const string &fqn)
void add_attribute_nocopy(D4Attribute *attr)
const vector< D4Attribute * > & attributes() const
D4AttributesIter attribute_begin()
Get an iterator to the start of the enumerations.
D4AttributesIter attribute_end()
Get an iterator to the end of the enumerations.
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
virtual void dump(ostream &strm) const
dumps information about this object
void erase_named_attribute(const string &name)
Erase an attribute from a specific container This method expects to find 'name' in the D4Attributes o...
vector< D4Attribute * >::iterator D4AttributesIter
vector< D4Attribute * >::const_iterator D4AttributesCIter
static ostream & LMarg(ostream &strm)
Definition DapIndent.cc:61
static void Indent()
Definition DapIndent.cc:44
static void UnIndent()
Definition DapIndent.cc:46
A class for error processing.
Definition Error.h:92
A class for software fault reporting.
Definition InternalErr.h:61
const char * get_doc()
Definition XMLWriter.cc:104
xmlTextWriterPtr get_writer() const
Definition XMLWriter.h:55
#define DBG(x)
Definition debug.h:58
top level DAP object to house generic methods
Definition AISConnect.cc:30
string escattr_xml(string s)
Definition escaping.cc:375
D4AttributeType StringToD4AttributeType(string s)
void downcase(string &s)
Definition util.cc:544
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:93
string D4AttributeTypeToString(D4AttributeType at)
AttrType get_dap2_AttrType(D4AttributeType d4_type)
@ Attr_float32
Definition AttrTable.h:86
@ Attr_container
Definition AttrTable.h:80
@ Attr_enum
Definition AttrTable.h:99
@ Attr_uint64
Definition AttrTable.h:97
@ Attr_string
Definition AttrTable.h:88
@ Attr_int8
Definition AttrTable.h:93
@ Attr_int32
Definition AttrTable.h:84
@ Attr_uint32
Definition AttrTable.h:85
@ Attr_url
Definition AttrTable.h:89
@ Attr_other_xml
Definition AttrTable.h:90
@ Attr_opaque
Definition AttrTable.h:100
@ Attr_uint16
Definition AttrTable.h:83
@ Attr_float64
Definition AttrTable.h:87
@ Attr_int64
Definition AttrTable.h:96
@ Attr_byte
Definition AttrTable.h:81
@ Attr_int16
Definition AttrTable.h:82