libdap Updated for version 3.20.10
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4Attributes.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., 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 "D4Attributes.h"
30#include "D4AttributeType.h"
31#include "InternalErr.h"
32
33#include "AttrTable.h"
34
35#include "util.h"
36#include "debug.h"
37#include "DapIndent.h"
38
39namespace libdap {
40
44string D4AttributeTypeToString(D4AttributeType at)
45{
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
98 case attr_container_c:
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{
111 downcase(s);
112
113 if (s == "container")
114 return attr_container_c;
115
116 else if (s == "byte")
117 return attr_byte_c;
118 else if (s == "int8")
119 return attr_int8_c;
120 else if (s == "uint8")
121 return attr_uint8_c;
122 else if (s == "int16")
123 return attr_int16_c;
124 else if (s == "uint16")
125 return attr_uint16_c;
126 else if (s == "int32")
127 return attr_int32_c;
128 else if (s == "uint32")
129 return attr_uint32_c;
130 else if (s == "int64")
131 return attr_int64_c;
132 else if (s == "uint64")
133 return attr_uint64_c;
134
135 else if (s == "float32")
136 return attr_float32_c;
137 else if (s == "float64")
138 return attr_float64_c;
139
140 else if (s == "string")
141 return attr_str_c;
142 else if (s == "url")
143 return attr_url_c;
144 else if (s == "otherxml")
145 return attr_otherxml_c;
146 else
147 return attr_null_c;
148}
149
150void
151D4Attribute::m_duplicate(const D4Attribute &src)
152{
153 d_name = src.d_name;
154 d_type = src.d_type;
155 d_values = src.d_values;
156 if (src.d_attributes)
157 d_attributes = new D4Attributes(*src.d_attributes);
158 else
159 d_attributes = 0;
160}
161
162D4Attribute::D4Attribute(const D4Attribute &src)
163{
164 m_duplicate(src);
165}
166
167D4Attribute::~D4Attribute()
168{
169 delete d_attributes;
170}
171
172D4Attribute &
173D4Attribute::operator=(const D4Attribute &rhs)
174{
175 if (this == &rhs) return *this;
176 m_duplicate(rhs);
177 return *this;
178}
179
180D4Attributes *
181D4Attribute::attributes()
182{
183 if (!d_attributes) d_attributes = new D4Attributes();
184 return d_attributes;
185}
186
195void
197{
198 // for every attribute in at, copy it to this.
199 for (AttrTable::Attr_iter i = at.attr_begin(), e = at.attr_end(); i != e; ++i) {
200 string name = at.get_name(i);
201 AttrType type = at.get_attr_type(i);
202
203 switch (type) {
204 case Attr_container: {
205 D4Attribute *a = new D4Attribute(name, attr_container_c);
206 D4Attributes *attributes = a->attributes(); // allocates a new object
207 attributes->transform_to_dap4(*at.get_attr_table(i));
208 add_attribute_nocopy(a);
209 break;
210 }
211 case Attr_byte: {
212 D4Attribute *a = new D4Attribute(name, attr_byte_c);
213 a->add_value_vector(*at.get_attr_vector(i));
214 add_attribute_nocopy(a);
215 break;
216 }
217 case Attr_int16: {
218 D4Attribute *a = new D4Attribute(name, attr_int16_c);
219 a->add_value_vector(*at.get_attr_vector(i));
220 add_attribute_nocopy(a);
221 break;
222 }
223 case Attr_uint16: {
224 D4Attribute *a = new D4Attribute(name, attr_uint16_c);
225 a->add_value_vector(*at.get_attr_vector(i));
226 add_attribute_nocopy(a);
227 break;
228 }
229 case Attr_int32: {
230 D4Attribute *a = new D4Attribute(name, attr_int32_c);
231 a->add_value_vector(*at.get_attr_vector(i));
232 add_attribute_nocopy(a);
233 break;
234 }
235 case Attr_uint32: {
236 D4Attribute *a = new D4Attribute(name, attr_uint32_c);
237 a->add_value_vector(*at.get_attr_vector(i));
238 add_attribute_nocopy(a);
239 break;
240 }
241 case Attr_float32: {
242 D4Attribute *a = new D4Attribute(name, attr_float32_c);
243 a->add_value_vector(*at.get_attr_vector(i));
244 add_attribute_nocopy(a);
245 break;
246 }
247 case Attr_float64: {
248 D4Attribute *a = new D4Attribute(name, attr_float64_c);
249 a->add_value_vector(*at.get_attr_vector(i));
250 add_attribute_nocopy(a);
251 break;
252 }
253 case Attr_string: {
254 D4Attribute *a = new D4Attribute(name, attr_str_c);
255 a->add_value_vector(*at.get_attr_vector(i));
256 add_attribute_nocopy(a);
257 break;
258 }
259 case Attr_url: {
260 D4Attribute *a = new D4Attribute(name, attr_url_c);
261 a->add_value_vector(*at.get_attr_vector(i));
262 add_attribute_nocopy(a);
263 break;
264 }
265 case Attr_other_xml: {
266 D4Attribute *a = new D4Attribute(name, attr_otherxml_c);
267 a->add_value_vector(*at.get_attr_vector(i));
268 add_attribute_nocopy(a);
269 break;
270 }
271 default:
272 throw InternalErr(__FILE__, __LINE__, "Unknown DAP2 attribute type in D4Attributes::copy_from_dap2()");
273 }
274 }
275}
276
277
278AttrType get_dap2_AttrType(D4AttributeType d4_type) {
279 switch (d4_type) {
280 case attr_container_c: { return Attr_container; }
281 case attr_byte_c: { return Attr_byte; }
282 case attr_int16_c: { return Attr_int16; }
283 case attr_uint16_c: { return Attr_uint16; }
284 case attr_int32_c: { return Attr_int32; }
285 case attr_uint32_c: { return Attr_uint32; }
286 case attr_float32_c: { return Attr_float32; }
287 case attr_float64_c: { return Attr_float64; }
288 case attr_str_c: { return Attr_string; }
289 case attr_url_c: { return Attr_url; }
290 case attr_otherxml_c: { return Attr_other_xml; }
291
292 case attr_int8_c: { return Attr_byte; }
293 case attr_uint8_c: { return Attr_byte; }
294 case attr_int64_c: {
295 throw InternalErr(__FILE__, __LINE__, "Unable to convert DAP4 attribute to DAP2. "
296 "There is no accepted DAP2 representation of Int64.");
297 }
298 case attr_uint64_c: {
299 throw InternalErr(__FILE__, __LINE__, "Unable to convert DAP4 attribute to DAP2. "
300 "There is no accepted DAP2 representation of UInt64.");
301 }
302 case attr_enum_c: {
303 throw InternalErr(__FILE__, __LINE__, "Unable to convert DAP4 attribute to DAP2. "
304 "There is no accepted DAP2 representation of Enumeration.");
305 }
306 case attr_opaque_c: {
307 throw InternalErr(__FILE__, __LINE__, "Unable to convert DAP4 attribute to DAP2. "
308 "There is no accepted DAP2 representation of Opaque.");
309 }
310
311 default:
312 throw InternalErr(__FILE__, __LINE__, "Unknown DAP4 attribute.");
313 }
314}
315
322{
323 // for every attribute in d4_attrs, copy it to d2_attr_table.
324 for (D4Attributes::D4AttributesIter i = attribute_begin(), e = attribute_end(); i != e; ++i) {
325 string name = (*i)->name();
326 D4AttributeType d4_attr_type = (*i)->type();
327 AttrType d2_attr_type = get_dap2_AttrType(d4_attr_type);
328 string d2_attr_type_name = AttrType_to_String(d2_attr_type);
329
330 switch (d4_attr_type) {
331 case attr_container_c: {
332 AttrTable *child_attr_table = new AttrTable();
333 child_attr_table->set_name(name);
334
335 (*i)->attributes()->transform_attrs_to_dap2(child_attr_table);
336 d2_attr_table->append_container(child_attr_table, name);
337 break;
338 }
339 default: {
340 for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
341 d2_attr_table->append_attr(name, d2_attr_type_name, *vi);
342 }
343
344 break;
345 }
346 }
347 }
348}
349
350#if 0
360void D4Attributes::load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
361{
362 // for every attribute in d4_attrs, copy it to d2_attr_table.
363 for (D4Attributes::D4AttributesIter i = d4_attrs->attribute_begin(), e = d4_attrs->attribute_end(); i != e; ++i) {
364 string name = (*i)->name();
365 D4AttributeType d4_attr_type = (*i)->type();
366 string d2_attr_type_name = AttrType_to_String(get_dap2_AttrType(d4_attr_type));
367
368#if 0
369 D4Attribute::D4AttributeIter vitr = (*i)->value_begin();
370 D4Attribute::D4AttributeIter end = (*i)->value_end();
371
372 vector<string> values;
373 for (; vitr != end; vitr++) {
374 values.push_back((*vitr));
375 }
376#endif
377
378 switch (d4_attr_type) {
379 case attr_container_c: {
380 // Attr_container
381 AttrTable *child_attr_table = new AttrTable();
382 child_attr_table->set_name(name);
383
384 load_AttrTable(child_attr_table, (*i)->attributes());
385 d2_attr_table->append_container(child_attr_table, name);
386 break;
387 }
388 default: {
389 for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
390 d2_attr_table->append_attr(name, d2_attr_type_name, *vi);
391 }
392
393 break;
394 }
395 }
396 }
397}
398
399
407AttrTable *D4Attributes::get_AttrTable(const string name)
408{
409 AttrTable *at = new AttrTable();
411#if 0
412 load_AttrTable(at, this);
413#endif
414 at->set_name(name);
415 return at;
416}
417#endif
418
419D4Attribute *
420D4Attributes::find_depth_first(const string &name, D4AttributesIter i)
421{
422 if (i == attribute_end())
423 return 0;
424 else if ((*i)->name() == name)
425 return *i;
426 else if ((*i)->type() == attr_container_c)
427 return find_depth_first(name, (*i)->attributes()->attribute_begin());
428 else
429 return find_depth_first(name, ++i);
430}
431
432D4Attribute *
433D4Attributes::find(const string &name)
434{
435 return find_depth_first(name, attribute_begin());
436}
437
441D4Attribute *
442D4Attributes::get(const string &fqn)
443{
444 // name1.name2.name3
445 // name1
446 // name1.name2
447 size_t pos = fqn.find('.');
448 string part = fqn.substr(0, pos);
449 string rest= "";
450
451 if (pos != string::npos)
452 rest = fqn.substr(pos + 1);
453
454 DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
455
456 if (!part.empty()) {
457 if (!rest.empty()) {
458 D4AttributesIter i = attribute_begin();
459 while (i != attribute_end()) {
460 if ((*i)->name() == part && (*i)->type() == attr_container_c)
461 return (*i)->attributes()->get(rest);
462 ++i;
463 }
464 }
465 else {
466 D4AttributesIter i = attribute_begin();
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
488{
489 for (auto &attr: d_attrs) {
490 if (attr->name() == name) {
491 delete attr;
492 attr = nullptr;
493 }
494 }
495 d_attrs.erase(remove(d_attrs.begin(), d_attrs.end(), nullptr), d_attrs.end());
496}
497
502void
503D4Attributes::erase(const string &fqn)
504{
505 // name1.name2.name3; part is name1 and rest is name2.name3
506 // name1; part is name1 and rest is ""
507 // name1.name2; part is name1 and rest is name2
508 size_t pos = fqn.find('.');
509 string part = fqn.substr(0, pos);
510 string rest= "";
511
512 if (pos != string::npos)
513 rest = fqn.substr(pos + 1);
514
515 if (!part.empty()) {
516 if (!rest.empty()) {
517 // in this case, we are not looking for a leaf node, so descend the
518 // attribute container hierarchy.
519 for (auto &a: d_attrs) {
520 if (a->name() == part && a->type() == attr_container_c) {
521 a->attributes()->erase(rest);
522 }
523 }
524 }
525 else {
527 }
528 }
529}
530
531void
532D4Attribute::print_dap4(XMLWriter &xml) const
533{
534 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
535 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
536 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
537 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
538 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", (const xmlChar*) D4AttributeTypeToString(type()).c_str()) < 0)
539 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
540
541 switch (type()) {
542 case attr_container_c:
543 // Just print xml when containing attributes. KY 2021-03-12
544 if (d_attributes)
545 d_attributes->print_dap4(xml);
546 break;
547
548 case attr_otherxml_c:
549 if (num_values() != 1)
550 throw Error("OtherXML attributes cannot be vector-valued.");
551 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) value(0).c_str()) < 0)
552 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
553 break;
554
555 default: {
556 // Assume only valid types make it into instances
557 D4AttributeCIter i = d_values.begin();//value_begin();
558 while (i != d_values.end()) {
559 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Value") < 0)
560 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
561
562 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
563 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
564
565 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
566 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
567 }
568
569 break;
570 }
571 }
572
573 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
574 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
575}
576
585void
586D4Attribute::dump(ostream &strm) const
587{
588 strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
589
590 DapIndent::Indent() ;
591
592 XMLWriter xml;
593 print_dap4(xml);
594 strm << DapIndent::LMarg << xml.get_doc() << flush;
595
596 DapIndent::UnIndent() ;
597}
598
599
600void
601D4Attributes::print_dap4(XMLWriter &xml) const
602{
603 if (empty())
604 return;
605
606 D4AttributesCIter i = d_attrs.begin();
607 while (i != d_attrs.end()) {
608 (*i++)->print_dap4(xml);
609 }
610}
611
620void
621D4Attributes::dump(ostream &strm) const
622{
623 strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
624
625 DapIndent::Indent() ;
626
627 XMLWriter xml;
628 print_dap4(xml);
629 strm << DapIndent::LMarg << xml.get_doc() << flush;
630
631 DapIndent::UnIndent() ;
632}
633
634
635} // namespace libdap
636
Contains the attributes for a dataset.
Definition AttrTable.h:143
virtual void dump(ostream &strm) const
dumps information about this object
void erase(const string &fqn)
Erase the given attribute.
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
D4Attribute * get(const string &fqn)
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 transform_attrs_to_dap2(AttrTable *d2_attr_table)
Copy the attributes from this D4Attributes object to a DAP2 AttrTable.
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...
A class for error processing.
Definition Error.h:94
A class for software fault reporting.
Definition InternalErr.h:65
top level DAP object to house generic methods
void downcase(string &s)
Definition util.cc:566
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:97
string D4AttributeTypeToString(D4AttributeType at)