D4Attributes.cc
// -*- mode: c++; c-basic-offset:4 -*-
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.
// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
#include "config.h"
#include <algorithm>
#include "D4AttributeType.h"
#include "D4Attributes.h"
#include "InternalErr.h"
#include "AttrTable.h"
#include "DapIndent.h"
#include "debug.h"
#include "escaping.h"
#include "util.h"
namespace libdap {
string D4AttributeTypeToString(D4AttributeType at) {
switch (at) {
case attr_null_c:
return "null";
case attr_byte_c:
return "Byte";
case attr_int16_c:
return "Int16";
case attr_uint16_c:
return "UInt16";
case attr_int32_c:
return "Int32";
case attr_uint32_c:
return "UInt32";
case attr_float32_c:
return "Float32";
case attr_float64_c:
return "Float64";
case attr_str_c:
return "String";
case attr_url_c:
return "Url";
// Added for DAP4
case attr_int8_c:
return "Int8";
case attr_uint8_c:
return "UInt8";
case attr_int64_c:
return "Int64";
case attr_uint64_c:
return "UInt64";
case attr_enum_c:
return "Enum";
case attr_opaque_c:
return "Opaque";
// These are specific to attributes while the other types are
// also supported by the variables. jhrg 4/17/13
case attr_container_c:
return "Container";
case attr_otherxml_c:
return "OtherXML";
default:
throw InternalErr(__FILE__, __LINE__, "Unsupported attribute type");
}
}
D4AttributeType StringToD4AttributeType(string s) {
downcase(s);
if (s == "container")
return attr_container_c;
else if (s == "byte")
return attr_byte_c;
else if (s == "int8")
return attr_int8_c;
else if (s == "uint8")
return attr_uint8_c;
else if (s == "int16")
return attr_int16_c;
else if (s == "uint16")
return attr_uint16_c;
else if (s == "int32")
return attr_int32_c;
else if (s == "uint32")
return attr_uint32_c;
else if (s == "int64")
return attr_int64_c;
else if (s == "uint64")
return attr_uint64_c;
else if (s == "float32")
return attr_float32_c;
else if (s == "float64")
return attr_float64_c;
else if (s == "string")
return attr_str_c;
else if (s == "url")
return attr_url_c;
else if (s == "otherxml")
return attr_otherxml_c;
else
return attr_null_c;
}
void D4Attribute::m_duplicate(const D4Attribute &src) {
d_name = src.d_name;
d_type = src.d_type;
d_values = src.d_values;
if (src.d_attributes)
d_attributes = new D4Attributes(*src.d_attributes);
else
d_attributes = 0;
}
D4Attribute::D4Attribute(const D4Attribute &src) { m_duplicate(src); }
D4Attribute::~D4Attribute() { delete d_attributes; }
D4Attribute &D4Attribute::operator=(const D4Attribute &rhs) {
if (this == &rhs)
return *this;
m_duplicate(rhs);
return *this;
}
D4Attributes *D4Attribute::attributes() {
if (!d_attributes)
d_attributes = new D4Attributes();
return d_attributes;
}
void D4Attributes::transform_to_dap4(AttrTable &at) {
// for every attribute in at, copy it to this.
for (AttrTable::Attr_iter i = at.attr_begin(), e = at.attr_end(); i != e; ++i) {
string name = at.get_name(i);
AttrType type = at.get_attr_type(i);
switch (type) {
case Attr_container: {
D4Attribute *a = new D4Attribute(name, attr_container_c);
D4Attributes *attributes = a->attributes(); // allocates a new object
attributes->transform_to_dap4(*at.get_attr_table(i));
add_attribute_nocopy(a);
break;
}
case Attr_byte: {
D4Attribute *a = new D4Attribute(name, attr_byte_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_int16: {
D4Attribute *a = new D4Attribute(name, attr_int16_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_uint16: {
D4Attribute *a = new D4Attribute(name, attr_uint16_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_int32: {
D4Attribute *a = new D4Attribute(name, attr_int32_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_uint32: {
D4Attribute *a = new D4Attribute(name, attr_uint32_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_float32: {
D4Attribute *a = new D4Attribute(name, attr_float32_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_float64: {
D4Attribute *a = new D4Attribute(name, attr_float64_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_string: {
D4Attribute *a = new D4Attribute(name, attr_str_c);
a->set_utf8_str_flag((*i)->is_utf8_str);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_url: {
D4Attribute *a = new D4Attribute(name, attr_url_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
case Attr_other_xml: {
D4Attribute *a = new D4Attribute(name, attr_otherxml_c);
a->add_value_vector(*at.get_attr_vector(i));
add_attribute_nocopy(a);
break;
}
default:
throw InternalErr(__FILE__, __LINE__, "Unknown DAP2 attribute type in D4Attributes::copy_from_dap2()");
}
}
}
AttrType get_dap2_AttrType(D4AttributeType d4_type) {
switch (d4_type) {
// These types are common between DAP4 and DAP2.
case attr_container_c: {
return Attr_container;
}
case attr_byte_c: {
return Attr_byte;
}
case attr_int16_c: {
return Attr_int16;
}
case attr_uint16_c: {
return Attr_uint16;
}
case attr_int32_c: {
return Attr_int32;
}
case attr_uint32_c: {
return Attr_uint32;
}
case attr_float32_c: {
return Attr_float32;
}
case attr_float64_c: {
return Attr_float64;
}
case attr_str_c: {
return Attr_string;
}
case attr_url_c: {
return Attr_url;
}
case attr_otherxml_c: {
return Attr_other_xml;
}
case attr_uint8_c: {
return Attr_byte;
}
// Types exclusive to DAP4
case attr_int8_c: {
return Attr_int8;
}
case attr_int64_c: {
return Attr_int64;
}
case attr_uint64_c: {
return Attr_uint64;
}
case attr_enum_c: {
return Attr_enum;
}
case attr_opaque_c: {
return Attr_opaque;
}
default:
throw InternalErr(__FILE__, __LINE__, "Unknown DAP4 attribute.");
}
}
void D4Attributes::transform_attrs_to_dap2(AttrTable *d2_attr_table) {
// for every attribute in d4_attrs, copy it to d2_attr_table.
for (D4Attributes::D4AttributesIter i = attribute_begin(), e = attribute_end(); i != e; ++i) {
string name = (*i)->name();
D4AttributeType d4_attr_type = (*i)->type();
AttrType d2_attr_type = get_dap2_AttrType(d4_attr_type);
string d2_attr_type_name = AttrType_to_String(d2_attr_type);
switch (d4_attr_type) {
case attr_container_c: {
AttrTable *child_attr_table = new AttrTable();
child_attr_table->set_name(name);
(*i)->attributes()->transform_attrs_to_dap2(child_attr_table);
d2_attr_table->append_container(child_attr_table, name);
break;
}
default: {
for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
d2_attr_table->append_attr(name, d2_attr_type_name, *vi, (*i)->get_utf8_str_flag());
}
break;
}
}
}
}
#if 0
void D4Attributes::load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
{
// for every attribute in d4_attrs, copy it to d2_attr_table.
for (D4Attributes::D4AttributesIter i = d4_attrs->attribute_begin(), e = d4_attrs->attribute_end(); i != e; ++i) {
string name = (*i)->name();
D4AttributeType d4_attr_type = (*i)->type();
string d2_attr_type_name = AttrType_to_String(get_dap2_AttrType(d4_attr_type));
#if 0
D4Attribute::D4AttributeIter vitr = (*i)->value_begin();
D4Attribute::D4AttributeIter end = (*i)->value_end();
vector<string> values;
for (; vitr != end; vitr++) {
values.push_back((*vitr));
}
#endif
switch (d4_attr_type) {
case attr_container_c: {
// Attr_container
AttrTable *child_attr_table = new AttrTable();
child_attr_table->set_name(name);
load_AttrTable(child_attr_table, (*i)->attributes());
d2_attr_table->append_container(child_attr_table, name);
break;
}
default: {
for (D4Attribute::D4AttributeIter vi = (*i)->value_begin(), ve = (*i)->value_end(); vi != ve; vi++) {
d2_attr_table->append_attr(name, d2_attr_type_name, *vi);
}
break;
}
}
}
}
AttrTable *D4Attributes::get_AttrTable(const string name)
{
AttrTable *at = new AttrTable();
transform_attrs_to_dap2(at);
#if 0
load_AttrTable(at, this);
#endif
at->set_name(name);
return at;
}
#endif
D4Attribute *D4Attributes::find_depth_first(const string &name, D4AttributesIter i) {
if (i == attribute_end())
return 0;
else if ((*i)->name() == name)
return *i;
else if ((*i)->type() == attr_container_c)
return find_depth_first(name, (*i)->attributes()->attribute_begin());
else
return find_depth_first(name, ++i);
}
D4Attribute *D4Attributes::find(const string &name) { return find_depth_first(name, attribute_begin()); }
D4Attribute *D4Attributes::get(const string &fqn) {
// name1.name2.name3
// name1
// name1.name2
size_t pos = fqn.find('.');
string part = fqn.substr(0, pos);
string rest = "";
if (pos != string::npos)
rest = fqn.substr(pos + 1);
DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
if (!part.empty()) {
if (!rest.empty()) {
D4AttributesIter i = attribute_begin();
while (i != attribute_end()) {
if ((*i)->name() == part && (*i)->type() == attr_container_c)
return (*i)->attributes()->get(rest);
++i;
}
} else {
D4AttributesIter i = attribute_begin();
while (i != attribute_end()) {
if ((*i)->name() == part)
return (*i);
++i;
}
}
}
return 0;
}
void D4Attributes::erase_named_attribute(const string &name) {
for (auto &attr : d_attrs) {
if (attr->name() == name) {
delete attr;
attr = nullptr;
}
}
d_attrs.erase(remove(d_attrs.begin(), d_attrs.end(), nullptr), d_attrs.end());
}
void D4Attributes::erase(const string &fqn) {
// name1.name2.name3; part is name1 and rest is name2.name3
// name1; part is name1 and rest is ""
// name1.name2; part is name1 and rest is name2
size_t pos = fqn.find('.');
string part = fqn.substr(0, pos);
string rest = "";
if (pos != string::npos)
rest = fqn.substr(pos + 1);
if (!part.empty()) {
if (!rest.empty()) {
// in this case, we are not looking for a leaf node, so descend the
// attribute container hierarchy.
for (auto &a : d_attrs) {
if (a->name() == part && a->type() == attr_container_c) {
a->attributes()->erase(rest);
}
}
} else {
erase_named_attribute(part);
}
}
}
void D4Attribute::print_dap4(XMLWriter &xml) const {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Attribute") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name", (const xmlChar *)name().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"type",
(const xmlChar *)D4AttributeTypeToString(type()).c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
switch (type()) {
case attr_container_c:
// Just print xml when containing attributes. KY 2021-03-12
if (d_attributes)
d_attributes->print_dap4(xml);
break;
case attr_otherxml_c:
if (num_values() != 1)
throw Error("OtherXML attributes cannot be vector-valued.");
if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar *)value(0).c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
break;
case attr_url_c:
case attr_str_c: {
// Need to escape special characters that xml doesn't allow. Note: the XML escaping is
// not the same as the das string escaping. See escattr_xml in the escaping.cc for details.
// KY 08-22-22
#if 0
D4AttributeCIter i = d_values.begin();//value_begin();
#endif
auto i = d_values.begin();
while (i != d_values.end()) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Value") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write value element");
#if 0
if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
#endif
string s = (get_utf8_str_flag()) ? (*i++) : escattr_xml(*i++);
if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar *)s.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end value element");
}
break;
}
default: {
// Assume only valid types make it into instances
D4AttributeCIter i = d_values.begin(); // value_begin();
while (i != d_values.end()) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Value") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write value element");
if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar *)(*i++).c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end value element");
}
break;
}
}
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
}
void D4Attribute::dump(ostream &strm) const {
strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
DapIndent::Indent();
XMLWriter xml;
print_dap4(xml);
strm << DapIndent::LMarg << xml.get_doc() << flush;
DapIndent::UnIndent();
}
void D4Attributes::print_dap4(XMLWriter &xml) const {
if (empty())
return;
D4AttributesCIter i = d_attrs.begin();
while (i != d_attrs.end()) {
(*i++)->print_dap4(xml);
}
}
bool D4Attribute::is_dap4_type(const std::string &path, std::vector<std::string> &inventory) {
bool ima_d4_attr = false;
switch (type()) {
case attr_int8_c:
case attr_int64_c:
case attr_uint64_c:
ima_d4_attr = true;
break;
case attr_container_c:
ima_d4_attr = attributes()->has_dap4_types(path, inventory);
break;
default:
break;
}
return ima_d4_attr;
}
bool D4Attributes::has_dap4_types(const std::string &path, std::vector<std::string> &inventory) const {
bool has_d4_attr = false;
for (const auto attr : attributes()) {
string attr_fqn = path + "@" + attr->name();
bool isa_d4_attr = attr->is_dap4_type(attr_fqn, inventory);
if (isa_d4_attr) {
inventory.emplace_back(D4AttributeTypeToString(attr->type()) + " " + attr_fqn);
}
has_d4_attr |= isa_d4_attr;
}
return has_d4_attr;
}
void D4Attributes::dump(ostream &strm) const {
strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
DapIndent::Indent();
XMLWriter xml;
print_dap4(xml);
strm << DapIndent::LMarg << xml.get_doc() << flush;
DapIndent::UnIndent();
}
} // namespace libdap
libdap::AttrTable
Contains the attributes for a dataset.
Definition AttrTable.h:150
libdap::AttrTable::append_container
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:517
libdap::AttrTable::set_name
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition AttrTable.cc:247
libdap::AttrTable::get_attr_table
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:699
libdap::AttrTable::attr_end
virtual Attr_iter attr_end()
Definition AttrTable.cc:798
libdap::AttrTable::get_attr_vector
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:738
libdap::AttrTable::append_attr
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:308
libdap::AttrTable::attr_begin
virtual Attr_iter attr_begin()
Definition AttrTable.cc:793
libdap::AttrTable::get_name
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:243
libdap::AttrTable::get_attr_type
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition AttrTable.cc:709
libdap::D4Attribute
Definition D4Attributes.h:43
libdap::D4Attribute::is_dap4_type
bool is_dap4_type(const std::string &path, std::vector< std::string > &inventory)
Definition D4Attributes.cc:633
libdap::D4Attribute::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition D4Attributes.cc:605
libdap::D4Attributes
Definition D4Attributes.h:98
libdap::D4Attributes::erase
void erase(const string &fqn)
Erase the given attribute.
Definition D4Attributes.cc:500
libdap::D4Attributes::transform_to_dap4
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
Definition D4Attributes.cc:184
libdap::D4Attributes::get
D4Attribute * get(const string &fqn)
Definition D4Attributes.cc:444
libdap::D4Attributes::attributes
const vector< D4Attribute * > & attributes() const
Definition D4Attributes.h:158
libdap::D4Attributes::attribute_begin
D4AttributesIter attribute_begin()
Get an iterator to the start of the enumerations.
Definition D4Attributes.h:143
libdap::D4Attributes::attribute_end
D4AttributesIter attribute_end()
Get an iterator to the end of the enumerations.
Definition D4Attributes.h:146
libdap::D4Attributes::transform_attrs_to_dap2
void transform_attrs_to_dap2(AttrTable *d2_attr_table)
Copy the attributes from this D4Attributes object to a DAP2 AttrTable.
Definition D4Attributes.cc:331
libdap::D4Attributes::has_dap4_types
bool has_dap4_types(const std::string &path, std::vector< std::string > &inventory) const
Definition D4Attributes.cc:656
libdap::D4Attributes::dump
virtual void dump(ostream &strm) const
dumps information about this object
Definition D4Attributes.cc:677
libdap::D4Attributes::erase_named_attribute
void erase_named_attribute(const string &name)
Erase an attribute from a specific container This method expects to find 'name' in the D4Attributes o...
Definition D4Attributes.cc:486
libdap::Error
A class for error processing.
Definition Error.h:92
libdap::InternalErr
A class for software fault reporting.
Definition InternalErr.h:61
libdap::XMLWriter
Definition XMLWriter.h:39
libdap
top level DAP object to house generic methods
Definition AlarmHandler.h:35
libdap::escattr_xml
string escattr_xml(string s)
Definition escaping.cc:375
libdap::downcase
void downcase(string &s)
Definition util.cc:544
libdap::AttrType_to_String
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:93
libdap::D4AttributeTypeToString
string D4AttributeTypeToString(D4AttributeType at)
Definition D4Attributes.cc:45
libdap::AttrType
AttrType
Definition AttrTable.h:78