libdap  Updated for version 3.20.6
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 //#define DODS_DEBUG
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 
39 namespace libdap {
40 
44 string 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 
109 D4AttributeType 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 
150 void
151 D4Attribute::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 
162 D4Attribute::D4Attribute(const D4Attribute &src)
163 {
164  m_duplicate(src);
165 }
166 
167 D4Attribute::~D4Attribute()
168 {
169  delete d_attributes;
170 }
171 
172 D4Attribute &
173 D4Attribute::operator=(const D4Attribute &rhs)
174 {
175  if (this == &rhs) return *this;
176  m_duplicate(rhs);
177  return *this;
178 }
179 
180 D4Attributes *
181 D4Attribute::attributes()
182 {
183  if (!d_attributes) d_attributes = new D4Attributes();
184  return d_attributes;
185 }
186 
195 void
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 
278 AttrType 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
351 
360 void 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 
407 AttrTable *D4Attributes::get_AttrTable(const string name)
408 {
409  AttrTable *at = new AttrTable();
410  transform_attrs_to_dap2(at);
411 #if 0
412  load_AttrTable(at, this);
413 #endif
414  at->set_name(name);
415  return at;
416 }
417 #endif
418 
419 D4Attribute *
420 D4Attributes::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 
432 D4Attribute *
433 D4Attributes::find(const string &name)
434 {
435  return find_depth_first(name, attribute_begin());
436 }
437 
441 D4Attribute *
442 D4Attributes::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 
478 void
479 D4Attribute::print_dap4(XMLWriter &xml) const
480 {
481  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
482  throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
483  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
484  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
485  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", (const xmlChar*) D4AttributeTypeToString(type()).c_str()) < 0)
486  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
487 
488  switch (type()) {
489  case attr_container_c:
490  if (!d_attributes)
491  throw InternalErr(__FILE__, __LINE__, "Null Attribute container");
492  d_attributes->print_dap4(xml);
493  break;
494 
495  case attr_otherxml_c:
496  if (num_values() != 1)
497  throw Error("OtherXML attributes cannot be vector-valued.");
498  if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) value(0).c_str()) < 0)
499  throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
500  break;
501 
502  default: {
503  // Assume only valid types make it into instances
504  D4AttributeCIter i = d_values.begin();//value_begin();
505  while (i != d_values.end()) {
506  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Value") < 0)
507  throw InternalErr(__FILE__, __LINE__, "Could not write value element");
508 
509  if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
510  throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
511 
512  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
513  throw InternalErr(__FILE__, __LINE__, "Could not end value element");
514  }
515 
516  break;
517  }
518  }
519 
520  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
521  throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
522 }
523 
532 void
533 D4Attribute::dump(ostream &strm) const
534 {
535  strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
536 
537  DapIndent::Indent() ;
538 
539  XMLWriter xml;
540  print_dap4(xml);
541  strm << DapIndent::LMarg << xml.get_doc() << flush;
542 
543  DapIndent::UnIndent() ;
544 }
545 
546 
547 void
548 D4Attributes::print_dap4(XMLWriter &xml) const
549 {
550  if (empty())
551  return;
552 
553  D4AttributesCIter i = d_attrs.begin();
554  while (i != d_attrs.end()) {
555  (*i++)->print_dap4(xml);
556  }
557 }
558 
567 void
568 D4Attributes::dump(ostream &strm) const
569 {
570  strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
571 
572  DapIndent::Indent() ;
573 
574  XMLWriter xml;
575  print_dap4(xml);
576  strm << DapIndent::LMarg << xml.get_doc() << flush;
577 
578  DapIndent::UnIndent() ;
579 }
580 
581 
582 } // namespace libdap
583 
virtual void dump(ostream &strm) const
dumps information about this object
virtual Attr_iter attr_end()
Definition: AttrTable.cc:719
void downcase(string &s)
Definition: util.cc:563
D4AttributesIter attribute_begin()
Get an iterator to the start of the enumerations.
Definition: D4Attributes.h:151
Contains the attributes for a dataset.
Definition: AttrTable.h:142
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:97
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
top level DAP object to house generic methods
Definition: AISConnect.cc:30
A class for software fault reporting.
Definition: InternalErr.h:64
void transform_attrs_to_dap2(AttrTable *d2_attr_table)
Copy the attributes from this D4Attributes object to a DAP2 AttrTable.
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:607
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:711
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:621
D4AttributesIter attribute_end()
Get an iterator to the end of the enumerations.
Definition: D4Attributes.h:154
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:653
D4Attribute * get(const string &fqn)
A class for error processing.
Definition: Error.h:92
string D4AttributeTypeToString(D4AttributeType at)
Definition: D4Attributes.cc:44
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:245
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
AttrType
Definition: AttrTable.h:81
virtual void dump(ostream &strm) const
dumps information about this object