libdap  Updated for version 3.20.3
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  default:
292  throw InternalErr(__FILE__, __LINE__, "Unknown DAP4 attribute");
293  }
294 }
295 
305 void D4Attributes::load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
306 {
307  // for every attribute in d4_attrs, copy it to d2_attr_table.
308  for (D4Attributes::D4AttributesIter i = d4_attrs->attribute_begin(), e = d4_attrs->attribute_end(); i != e; ++i) {
309  string name = (*i)->name();
310  D4AttributeType d4_attr_type = (*i)->type();
311  AttrType d2_attr_type = get_dap2_AttrType(d4_attr_type);
312  string d2_attr_type_name = AttrType_to_String(d2_attr_type);
313 
314  D4Attribute::D4AttributeIter vitr = (*i)->value_begin();
315  D4Attribute::D4AttributeIter end = (*i)->value_end();
316 
317  vector<string> values;
318  for (; vitr != end; vitr++) {
319  values.push_back((*vitr));
320  }
321 
322  switch (d4_attr_type) {
323  case attr_container_c: {
324  // Attr_container
325  AttrTable *child_attr_table = new AttrTable();
326  child_attr_table->set_name(name);
327 
328  load_AttrTable(child_attr_table, (*i)->attributes());
329  d2_attr_table->append_container(child_attr_table, name);
330  break;
331  }
332  default: {
333  d2_attr_table->append_attr(name, d2_attr_type_name, &values);
334  break;
335  }
336  }
337  }
338 }
339 
348 {
349  AttrTable *my_pretty_pony = new AttrTable();
350  load_AttrTable(my_pretty_pony, this);
351  my_pretty_pony->set_name(name);
352  return my_pretty_pony;
353 }
354 
355 
356 D4Attribute *
357 D4Attributes::find_depth_first(const string &name, D4AttributesIter i)
358 {
359  if (i == attribute_end())
360  return 0;
361  else if ((*i)->name() == name)
362  return *i;
363  else if ((*i)->type() == attr_container_c)
364  return find_depth_first(name, (*i)->attributes()->attribute_begin());
365  else
366  return find_depth_first(name, ++i);
367 }
368 
369 D4Attribute *
370 D4Attributes::find(const string &name)
371 {
372  return find_depth_first(name, attribute_begin());
373 }
374 
378 D4Attribute *
379 D4Attributes::get(const string &fqn)
380 {
381  // name1.name2.name3
382  // name1
383  // name1.name2
384  size_t pos = fqn.find('.');
385  string part = fqn.substr(0, pos);
386  string rest= "";
387 
388  if (pos != string::npos)
389  rest = fqn.substr(pos + 1);
390 
391  DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
392 
393  if (!part.empty()) {
394  if (!rest.empty()) {
395  D4AttributesIter i = attribute_begin();
396  while (i != attribute_end()) {
397  if ((*i)->name() == part && (*i)->type() == attr_container_c)
398  return (*i)->attributes()->get(rest);
399  ++i;
400  }
401  }
402  else {
403  D4AttributesIter i = attribute_begin();
404  while (i != attribute_end()) {
405  if ((*i)->name() == part)
406  return (*i);
407  ++i;
408  }
409  }
410  }
411 
412  return 0;
413 }
414 
415 void
416 D4Attribute::print_dap4(XMLWriter &xml) const
417 {
418  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
419  throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
420  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
421  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
422  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", (const xmlChar*) D4AttributeTypeToString(type()).c_str()) < 0)
423  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
424 
425  switch (type()) {
426  case attr_container_c:
427  if (!d_attributes)
428  throw InternalErr(__FILE__, __LINE__, "Null Attribute container");
429  d_attributes->print_dap4(xml);
430  break;
431 
432  case attr_otherxml_c:
433  if (num_values() != 1)
434  throw Error("OtherXML attributes cannot be vector-valued.");
435  if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) value(0).c_str()) < 0)
436  throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
437  break;
438 
439  default: {
440  // Assume only valid types make it into instances
441  D4AttributeCIter i = d_values.begin();//value_begin();
442  while (i != d_values.end()) {
443  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Value") < 0)
444  throw InternalErr(__FILE__, __LINE__, "Could not write value element");
445 
446  if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
447  throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
448 
449  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
450  throw InternalErr(__FILE__, __LINE__, "Could not end value element");
451  }
452 
453  break;
454  }
455  }
456 
457  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
458  throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
459 }
460 
469 void
470 D4Attribute::dump(ostream &strm) const
471 {
472  strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
473 
474  DapIndent::Indent() ;
475 
476  XMLWriter xml;
477  print_dap4(xml);
478  strm << DapIndent::LMarg << xml.get_doc() << flush;
479 
480  DapIndent::UnIndent() ;
481 }
482 
483 
484 void
485 D4Attributes::print_dap4(XMLWriter &xml) const
486 {
487  if (empty())
488  return;
489 
490  D4AttributesCIter i = d_attrs.begin();
491  while (i != d_attrs.end()) {
492  (*i++)->print_dap4(xml);
493  }
494 }
495 
504 void
505 D4Attributes::dump(ostream &strm) const
506 {
507  strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
508 
509  DapIndent::Indent() ;
510 
511  XMLWriter xml;
512  print_dap4(xml);
513  strm << DapIndent::LMarg << xml.get_doc() << flush;
514 
515  DapIndent::UnIndent() ;
516 }
517 
518 
519 } // namespace libdap
520 
AttrTable * get_AttrTable(const std::string name)
copy attributes from DAP4 to DAP2
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:146
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: AlarmHandler.h:35
A class for software fault reporting.
Definition: InternalErr.h:64
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:149
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
static void load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
Transfer DAP4 attributes to a DAP2 AttrTable object.
AttrType
Definition: AttrTable.h:81
virtual void dump(ostream &strm) const
dumps information about this object