libdap  Updated for version 3.19.1
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 
38 namespace libdap {
39 
43 string D4AttributeTypeToString(D4AttributeType at)
44 {
45  switch(at) {
46  case attr_null_c:
47  return "null";
48 
49  case attr_byte_c:
50  return "Byte";
51 
52  case attr_int16_c:
53  return "Int16";
54 
55  case attr_uint16_c:
56  return "UInt16";
57 
58  case attr_int32_c:
59  return "Int32";
60 
61  case attr_uint32_c:
62  return "UInt32";
63 
64  case attr_float32_c:
65  return "Float32";
66 
67  case attr_float64_c:
68  return "Float64";
69 
70  case attr_str_c:
71  return "String";
72 
73  case attr_url_c:
74  return "Url";
75 
76  // Added for DAP4
77  case attr_int8_c:
78  return "Int8";
79 
80  case attr_uint8_c:
81  return "UInt8";
82 
83  case attr_int64_c:
84  return "Int64";
85 
86  case attr_uint64_c:
87  return "UInt64";
88 
89  case attr_enum_c:
90  return "Enum";
91 
92  case attr_opaque_c:
93  return "Opaque";
94 
95  // These are specific to attributes while the other types are
96  // also supported by the variables. jhrg 4/17/13
97  case attr_container_c:
98  return "Container";
99 
100  case attr_otherxml_c:
101  return "OtherXML";
102 
103  default:
104  throw InternalErr(__FILE__, __LINE__, "Unsupported attribute type");
105  }
106 }
107 
108 D4AttributeType StringToD4AttributeType(string s)
109 {
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 
149 void
150 D4Attribute::m_duplicate(const D4Attribute &src)
151 {
152  d_name = src.d_name;
153  d_type = src.d_type;
154  d_values = src.d_values;
155  if (src.d_attributes)
156  d_attributes = new D4Attributes(*src.d_attributes);
157  else
158  d_attributes = 0;
159 }
160 
161 D4Attribute::D4Attribute(const D4Attribute &src)
162 {
163  m_duplicate(src);
164 }
165 
166 D4Attribute::~D4Attribute()
167 {
168  delete d_attributes;
169 }
170 
171 D4Attribute &
172 D4Attribute::operator=(const D4Attribute &rhs)
173 {
174  if (this == &rhs) return *this;
175  m_duplicate(rhs);
176  return *this;
177 }
178 
179 D4Attributes *
180 D4Attribute::attributes()
181 {
182  if (!d_attributes) d_attributes = new D4Attributes();
183  return d_attributes;
184 }
185 
194 void
196 {
197  // for every attribute in at, copy it to this.
198  for (AttrTable::Attr_iter i = at.attr_begin(), e = at.attr_end(); i != e; ++i) {
199  string name = at.get_name(i);
200  AttrType type = at.get_attr_type(i);
201 
202  switch (type) {
203  case Attr_container: {
204  D4Attribute *a = new D4Attribute(name, attr_container_c);
205  D4Attributes *attributes = a->attributes(); // allocates a new object
206  attributes->transform_to_dap4(*at.get_attr_table(i));
207  add_attribute_nocopy(a);
208  break;
209  }
210  case Attr_byte: {
211  D4Attribute *a = new D4Attribute(name, attr_byte_c);
212  a->add_value_vector(*at.get_attr_vector(i));
213  add_attribute_nocopy(a);
214  break;
215  }
216  case Attr_int16: {
217  D4Attribute *a = new D4Attribute(name, attr_int16_c);
218  a->add_value_vector(*at.get_attr_vector(i));
219  add_attribute_nocopy(a);
220  break;
221  }
222  case Attr_uint16: {
223  D4Attribute *a = new D4Attribute(name, attr_uint16_c);
224  a->add_value_vector(*at.get_attr_vector(i));
225  add_attribute_nocopy(a);
226  break;
227  }
228  case Attr_int32: {
229  D4Attribute *a = new D4Attribute(name, attr_int32_c);
230  a->add_value_vector(*at.get_attr_vector(i));
231  add_attribute_nocopy(a);
232  break;
233  }
234  case Attr_uint32: {
235  D4Attribute *a = new D4Attribute(name, attr_uint32_c);
236  a->add_value_vector(*at.get_attr_vector(i));
237  add_attribute_nocopy(a);
238  break;
239  }
240  case Attr_float32: {
241  D4Attribute *a = new D4Attribute(name, attr_float32_c);
242  a->add_value_vector(*at.get_attr_vector(i));
243  add_attribute_nocopy(a);
244  break;
245  }
246  case Attr_float64: {
247  D4Attribute *a = new D4Attribute(name, attr_float64_c);
248  a->add_value_vector(*at.get_attr_vector(i));
249  add_attribute_nocopy(a);
250  break;
251  }
252  case Attr_string: {
253  D4Attribute *a = new D4Attribute(name, attr_str_c);
254  a->add_value_vector(*at.get_attr_vector(i));
255  add_attribute_nocopy(a);
256  break;
257  }
258  case Attr_url: {
259  D4Attribute *a = new D4Attribute(name, attr_url_c);
260  a->add_value_vector(*at.get_attr_vector(i));
261  add_attribute_nocopy(a);
262  break;
263  }
264  case Attr_other_xml: {
265  D4Attribute *a = new D4Attribute(name, attr_otherxml_c);
266  a->add_value_vector(*at.get_attr_vector(i));
267  add_attribute_nocopy(a);
268  break;
269  }
270  default:
271  throw InternalErr(__FILE__, __LINE__, "Unknown DAP2 attribute type in D4Attributes::copy_from_dap2()");
272  }
273  }
274 }
275 
276 
277 AttrType get_dap2_AttrType(D4AttributeType d4_type){
278  switch (d4_type) {
279  case attr_container_c: { return Attr_container; }
280  case attr_byte_c: { return Attr_byte; }
281  case attr_int16_c: { return Attr_int16; }
282  case attr_uint16_c: { return Attr_uint16; }
283  case attr_int32_c: { return Attr_int32; }
284  case attr_uint32_c: { return Attr_uint32; }
285  case attr_float32_c: { return Attr_float32; }
286  case attr_float64_c: { return Attr_float64; }
287  case attr_str_c: { return Attr_string; }
288  case attr_url_c: { return Attr_url; }
289  case attr_otherxml_c: { return Attr_other_xml; }
290  default:
291  throw InternalErr(__FILE__, __LINE__, "Unknown DAP4 attribute");
292  }
293 }
294 
295 
296 void
297 D4Attributes::load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
298 {
299  // cerr << __func__ << "() - Loading attribute table: '" << d2_attr_table->get_name() << "' addr: " << (void *)d2_attr_table << endl;
300 
301  // for every attribute in at, copy it to this.
302  for ( D4Attributes::D4AttributesIter i = d4_attrs->attribute_begin(), e = d4_attrs->attribute_end(); i != e; ++i) {
303  string name = (*i)->name();
304  D4AttributeType d4_attr_type = (*i)->type();
305  AttrType d2_attr_type = get_dap2_AttrType(d4_attr_type);
306  string d2_attr_type_name = AttrType_to_String(d2_attr_type);
307 
308  D4Attribute::D4AttributeIter vitr =(*i)->value_begin();
309  D4Attribute::D4AttributeIter end =(*i)->value_end();
310 
311  vector<string> values;
312  for(;vitr!=end; vitr++){
313  values.push_back((*vitr));
314  }
315 
316  switch (d4_attr_type) {
317  case attr_container_c: {
318  // Attr_container
319  AttrTable *child_attr_table = new AttrTable();
320  child_attr_table->set_name(name);
321  // cerr << __func__ << "() - Created child attribute table: " << name << " addr: " << (void *)child_attr_table << endl;
322  load_AttrTable(child_attr_table,(*i)->attributes());
323  d2_attr_table->append_container(child_attr_table,name);
324  break;
325  }
326  default:{
327  // cerr << __func__ << "() - "<< name << " has " << values.size() << " value(s). d2_attr_type_name: " << d2_attr_type_name << endl;
328  d2_attr_table->append_attr(name,d2_attr_type_name, &values);
329  break;
330  }
331  }
332  }
333 }
334 
335 
344 {
345  AttrTable *my_pretty_pony = new AttrTable();
346  load_AttrTable(my_pretty_pony, this);
347  my_pretty_pony->set_name(name);
348  return my_pretty_pony;
349 }
350 
351 
352 D4Attribute *
353 D4Attributes::find_depth_first(const string &name, D4AttributesIter i)
354 {
355  if (i == attribute_end())
356  return 0;
357  else if ((*i)->name() == name)
358  return *i;
359  else if ((*i)->type() == attr_container_c)
360  return find_depth_first(name, (*i)->attributes()->attribute_begin());
361  else
362  return find_depth_first(name, ++i);
363 }
364 
365 D4Attribute *
366 D4Attributes::find(const string &name)
367 {
368  return find_depth_first(name, attribute_begin());
369 }
370 
374 D4Attribute *
375 D4Attributes::get(const string &fqn)
376 {
377  // name1.name2.name3
378  // name1
379  // name1.name2
380  size_t pos = fqn.find('.');
381  string part = fqn.substr(0, pos);
382  string rest= "";
383 
384  if (pos != string::npos)
385  rest = fqn.substr(pos + 1);
386 
387  DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
388 
389  if (!part.empty()) {
390  if (!rest.empty()) {
391  D4AttributesIter i = attribute_begin();
392  while (i != attribute_end()) {
393  if ((*i)->name() == part && (*i)->type() == attr_container_c)
394  return (*i)->attributes()->get(rest);
395  ++i;
396  }
397  }
398  else {
399  D4AttributesIter i = attribute_begin();
400  while (i != attribute_end()) {
401  if ((*i)->name() == part)
402  return (*i);
403  ++i;
404  }
405  }
406  }
407 
408  return 0;
409 }
410 
411 void
412 D4Attribute::print_dap4(XMLWriter &xml) const
413 {
414  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
415  throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
416  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
417  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
418  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", (const xmlChar*) D4AttributeTypeToString(type()).c_str()) < 0)
419  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
420 
421  switch (type()) {
422  case attr_container_c:
423  if (!d_attributes)
424  throw InternalErr(__FILE__, __LINE__, "Null Attribute container");
425  d_attributes->print_dap4(xml);
426  break;
427 
428  case attr_otherxml_c:
429  if (num_values() != 1)
430  throw Error("OtherXML attributes cannot be vector-valued.");
431  if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) value(0).c_str()) < 0)
432  throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
433  break;
434 
435  default: {
436  // Assume only valid types make it into instances
437  D4AttributeCIter i = d_values.begin();//value_begin();
438  while (i != d_values.end()) {
439  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Value") < 0)
440  throw InternalErr(__FILE__, __LINE__, "Could not write value element");
441 
442  if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
443  throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
444 
445  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
446  throw InternalErr(__FILE__, __LINE__, "Could not end value element");
447  }
448 
449  break;
450  }
451  }
452 
453  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
454  throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
455 }
456 
465 void
466 D4Attribute::dump(ostream &strm) const
467 {
468  strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
469 
470  DapIndent::Indent() ;
471 
472  XMLWriter xml;
473  print_dap4(xml);
474  strm << DapIndent::LMarg << xml.get_doc() << flush;
475 
476  DapIndent::UnIndent() ;
477 }
478 
479 
480 void
481 D4Attributes::print_dap4(XMLWriter &xml) const
482 {
483  if (empty())
484  return;
485 
486  D4AttributesCIter i = d_attrs.begin();
487  while (i != d_attrs.end()) {
488  (*i++)->print_dap4(xml);
489  }
490 }
491 
500 void
501 D4Attributes::dump(ostream &strm) const
502 {
503  strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
504 
505  DapIndent::Indent() ;
506 
507  XMLWriter xml;
508  print_dap4(xml);
509  strm << DapIndent::LMarg << xml.get_doc() << flush;
510 
511  DapIndent::UnIndent() ;
512 }
513 
514 
515 } // namespace libdap
516 
libdap::D4AttributeTypeToString
string D4AttributeTypeToString(D4AttributeType at)
Definition: D4Attributes.cc:43
libdap::AttrTable::attr_end
virtual Attr_iter attr_end()
Definition: AttrTable.cc:718
libdap::D4Attribute
Definition: D4Attributes.h:44
libdap::D4Attributes::attribute_end
D4AttributesIter attribute_end()
Get an iterator to the end of the enumerations.
Definition: D4Attributes.h:149
libdap::XMLWriter
Definition: XMLWriter.h:39
libdap::AttrType_to_String
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:96
libdap::Error
A class for error processing.
Definition: Error.h:90
libdap::InternalErr
A class for software fault reporting.
Definition: InternalErr.h:64
libdap::AttrTable::set_name
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:244
libdap::D4Attributes::get_AttrTable
AttrTable * get_AttrTable(const std::string name)
copy attributes from DAP4 to DAP2
Definition: D4Attributes.cc:343
libdap
Definition: AlarmHandler.h:35
libdap::D4Attributes::transform_to_dap4
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
Definition: D4Attributes.cc:195
libdap::AttrTable::get_attr_table
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:606
libdap::D4Attributes::get
D4Attribute * get(const string &fqn)
Definition: D4Attributes.cc:375
libdap::D4Attribute::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: D4Attributes.cc:466
libdap::AttrTable::get_attr_vector
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:652
libdap::AttrTable
Contains the attributes for a dataset.
Definition: AttrTable.h:142
libdap::D4Attributes::attribute_begin
D4AttributesIter attribute_begin()
Get an iterator to the start of the enumerations.
Definition: D4Attributes.h:146
libdap::D4Attributes::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition: D4Attributes.cc:501
libdap::D4Attributes
Definition: D4Attributes.h:94
libdap::AttrTable::attr_begin
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:710
libdap::AttrType
AttrType
Definition: AttrTable.h:81
libdap::AttrTable::get_name
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:237
libdap::AttrTable::get_attr_type
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:620
libdap::downcase
void downcase(string &s)
Definition: util.cc:563