libdap  Updated for version 3.17.0
D4Attributes.cc
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2013 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 
00025 #include "config.h"
00026 
00027 //#define DODS_DEBUG
00028 
00029 #include "D4Attributes.h"
00030 #include "D4AttributeType.h"
00031 #include "InternalErr.h"
00032 
00033 #include "AttrTable.h"
00034 
00035 #include "util.h"
00036 #include "debug.h"
00037 
00038 namespace libdap {
00039 
00043 string D4AttributeTypeToString(D4AttributeType at)
00044 {
00045     switch(at) {
00046         case attr_null_c:
00047             return "null";
00048 
00049         case attr_byte_c:
00050             return "Byte";
00051 
00052         case attr_int16_c:
00053             return "Int16";
00054 
00055         case attr_uint16_c:
00056             return "UInt16";
00057 
00058         case attr_int32_c:
00059             return "Int32";
00060 
00061         case attr_uint32_c:
00062             return "UInt32";
00063 
00064         case attr_float32_c:
00065             return "Float32";
00066 
00067         case attr_float64_c:
00068             return "Float64";
00069 
00070         case attr_str_c:
00071             return "String";
00072 
00073         case attr_url_c:
00074             return "Url";
00075 
00076         // Added for DAP4
00077         case attr_int8_c:
00078             return "Int8";
00079 
00080         case attr_uint8_c:
00081             return "UInt8";
00082 
00083         case attr_int64_c:
00084             return "Int64";
00085 
00086         case attr_uint64_c:
00087             return "UInt64";
00088 
00089         case attr_enum_c:
00090             return "Enum";
00091 
00092         case attr_opaque_c:
00093             return "Opaque";
00094 
00095         // These are specific to attributes while the other types are
00096         // also supported by the variables. jhrg 4/17/13
00097         case attr_container_c:
00098             return "Container";
00099 
00100         case attr_otherxml_c:
00101             return "OtherXML";
00102 
00103         default:
00104             throw InternalErr(__FILE__, __LINE__, "Unsupported attribute type");
00105     }
00106 }
00107 
00108 D4AttributeType StringToD4AttributeType(string s)
00109 {
00110     downcase(s);
00111 
00112     if (s == "container")
00113         return attr_container_c;
00114 
00115     else if (s == "byte")
00116         return attr_byte_c;
00117     else if (s == "int8")
00118         return attr_int8_c;
00119     else if (s == "uint8")
00120         return attr_uint8_c;
00121     else if (s == "int16")
00122         return attr_int16_c;
00123     else if (s == "uint16")
00124         return attr_uint16_c;
00125     else if (s == "int32")
00126         return attr_int32_c;
00127     else if (s == "uint32")
00128         return attr_uint32_c;
00129     else if (s == "int64")
00130         return attr_int64_c;
00131     else if (s == "uint64")
00132         return attr_uint64_c;
00133 
00134     else if (s == "float32")
00135         return attr_float32_c;
00136     else if (s == "float64")
00137         return attr_float64_c;
00138 
00139     else if (s == "string")
00140         return attr_str_c;
00141     else if (s == "url")
00142         return attr_url_c;
00143     else if (s == "otherxml")
00144         return attr_otherxml_c;
00145     else
00146         return attr_null_c;
00147 }
00148 
00149 void
00150 D4Attribute::m_duplicate(const D4Attribute &src)
00151 {
00152     d_name = src.d_name;
00153     d_type = src.d_type;
00154     d_values = src.d_values;
00155     if (src.d_attributes)
00156         d_attributes = new D4Attributes(*src.d_attributes);
00157     else
00158         d_attributes = 0;
00159 }
00160 
00161 D4Attribute::D4Attribute(const D4Attribute &src)
00162 {
00163     m_duplicate(src);
00164 }
00165 
00166 D4Attribute::~D4Attribute()
00167 {
00168     delete d_attributes;
00169 }
00170 
00171 D4Attribute &
00172 D4Attribute::operator=(const D4Attribute &rhs)
00173 {
00174     if (this == &rhs) return *this;
00175     m_duplicate(rhs);
00176     return *this;
00177 }
00178 
00179 D4Attributes *
00180 D4Attribute::attributes()
00181 {
00182     if (!d_attributes) d_attributes = new D4Attributes();
00183     return d_attributes;
00184 }
00185 
00193 void
00194 D4Attributes::transform_to_dap4(AttrTable &at)
00195 {
00196         // for every attribute in at, copy it to this.
00197         for (AttrTable::Attr_iter i = at.attr_begin(), e = at.attr_end(); i != e; ++i) {
00198                 string name = at.get_name(i);
00199                 AttrType type = at.get_attr_type(i);
00200 
00201                 switch (type) {
00202                 case Attr_container: {
00203                         D4Attribute *a = new D4Attribute(name, attr_container_c);
00204                         D4Attributes *attributes = a->attributes(); // allocates a new object
00205                         attributes->transform_to_dap4(*at.get_attr_table(i));
00206                         add_attribute_nocopy(a);
00207                         break;
00208                 }
00209                 case Attr_byte: {
00210                         D4Attribute *a = new D4Attribute(name, attr_byte_c);
00211                         a->add_value_vector(*at.get_attr_vector(i));
00212                         add_attribute_nocopy(a);
00213                         break;
00214                 }
00215                 case Attr_int16: {
00216                         D4Attribute *a = new D4Attribute(name, attr_int16_c);
00217                         a->add_value_vector(*at.get_attr_vector(i));
00218                         add_attribute_nocopy(a);
00219                         break;
00220                 }
00221                 case Attr_uint16: {
00222                         D4Attribute *a = new D4Attribute(name, attr_uint16_c);
00223                         a->add_value_vector(*at.get_attr_vector(i));
00224                         add_attribute_nocopy(a);
00225                         break;
00226                 }
00227                 case Attr_int32: {
00228                         D4Attribute *a = new D4Attribute(name, attr_int32_c);
00229                         a->add_value_vector(*at.get_attr_vector(i));
00230                         add_attribute_nocopy(a);
00231                         break;
00232                 }
00233                 case Attr_uint32: {
00234                         D4Attribute *a = new D4Attribute(name, attr_uint32_c);
00235                         a->add_value_vector(*at.get_attr_vector(i));
00236                         add_attribute_nocopy(a);
00237                         break;
00238                 }
00239                 case Attr_float32: {
00240                         D4Attribute *a = new D4Attribute(name, attr_float32_c);
00241                         a->add_value_vector(*at.get_attr_vector(i));
00242                         add_attribute_nocopy(a);
00243                         break;
00244                 }
00245                 case Attr_float64: {
00246                         D4Attribute *a = new D4Attribute(name, attr_float64_c);
00247                         a->add_value_vector(*at.get_attr_vector(i));
00248                         add_attribute_nocopy(a);
00249                         break;
00250                 }
00251                 case Attr_string: {
00252                         D4Attribute *a = new D4Attribute(name, attr_str_c);
00253                         a->add_value_vector(*at.get_attr_vector(i));
00254                         add_attribute_nocopy(a);
00255                         break;
00256                 }
00257                 case Attr_url: {
00258                         D4Attribute *a = new D4Attribute(name, attr_url_c);
00259                         a->add_value_vector(*at.get_attr_vector(i));
00260                         add_attribute_nocopy(a);
00261                         break;
00262                 }
00263                 case Attr_other_xml: {
00264                         D4Attribute *a = new D4Attribute(name, attr_otherxml_c);
00265                         a->add_value_vector(*at.get_attr_vector(i));
00266                         add_attribute_nocopy(a);
00267                         break;
00268                 }
00269                 default:
00270                         throw InternalErr(__FILE__, __LINE__, "Unknown DAP2 attribute type in D4Attributes::copy_from_dap2()");
00271                 }
00272         }
00273 }
00274 
00275 D4Attribute *
00276 D4Attributes::find_depth_first(const string &name, D4AttributesIter i)
00277 {
00278     if (i == attribute_end())
00279         return 0;
00280     else if ((*i)->name() == name)
00281         return *i;
00282     else if ((*i)->type() == attr_container_c)
00283         return find_depth_first(name, (*i)->attributes()->attribute_begin());
00284     else
00285         return find_depth_first(name, ++i);
00286 }
00287 
00288 D4Attribute *
00289 D4Attributes::find(const string &name)
00290 {
00291     return find_depth_first(name, attribute_begin());
00292 }
00293 
00297 D4Attribute *
00298 D4Attributes::get(const string &fqn)
00299 {
00300     // name1.name2.name3
00301     // name1
00302     // name1.name2
00303     size_t pos = fqn.find('.');
00304     string part = fqn.substr(0, pos);
00305     string rest= "";
00306 
00307     if (pos != string::npos)
00308         rest = fqn.substr(pos + 1);
00309 
00310     DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
00311 
00312     if (!part.empty()) {
00313         if (!rest.empty()) {
00314             D4AttributesIter i = attribute_begin();
00315             while (i != attribute_end()) {
00316                 if ((*i)->name() == part && (*i)->type() == attr_container_c)
00317                     return (*i)->attributes()->get(rest);
00318                 ++i;
00319             }
00320         }
00321         else {
00322             D4AttributesIter i = attribute_begin();
00323             while (i != attribute_end()) {
00324                 if ((*i)->name() == part)
00325                     return (*i);
00326                 ++i;
00327             }
00328         }
00329     }
00330 
00331     return 0;
00332 }
00333 
00334 void
00335 D4Attribute::print_dap4(XMLWriter &xml) const
00336 {
00337     if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
00338         throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
00339     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
00340         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
00341     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", (const xmlChar*) D4AttributeTypeToString(type()).c_str()) < 0)
00342         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
00343 
00344     switch (type()) {
00345         case attr_container_c:
00346             if (!d_attributes)
00347                 throw InternalErr(__FILE__, __LINE__, "Null Attribute container");
00348             d_attributes->print_dap4(xml);
00349             break;
00350 
00351         case attr_otherxml_c:
00352             if (num_values() != 1)
00353                 throw Error("OtherXML attributes cannot be vector-valued.");
00354             if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) value(0).c_str()) < 0)
00355                 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
00356             break;
00357 
00358         default: {
00359             // Assume only valid types make it into instances
00360             D4AttributeCIter i = d_values.begin();//value_begin();
00361             while (i != d_values.end()) {
00362                 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Value") < 0)
00363                     throw InternalErr(__FILE__, __LINE__, "Could not write value element");
00364 
00365                 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
00366                     throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
00367 
00368                 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
00369                     throw InternalErr(__FILE__, __LINE__, "Could not end value element");
00370             }
00371 
00372             break;
00373         }
00374     }
00375 
00376     if (xmlTextWriterEndElement(xml.get_writer()) < 0)
00377         throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
00378 }
00379 
00380 void
00381 D4Attributes::print_dap4(XMLWriter &xml) const
00382 {
00383     if (empty())
00384         return;
00385 
00386     D4AttributesCIter i = d_attrs.begin();
00387     while (i != d_attrs.end()) {
00388         (*i++)->print_dap4(xml);
00389     }
00390 }
00391 
00392 } // namespace libdap
00393