libdap  Updated for version 3.17.0
D4Enum.cc
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2013 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 #include "config.h"
00027 
00028 //#define DODS_DEBUG 1
00029 
00030 #include <cassert>
00031 #include <sstream>
00032 
00033 #include <libxml/encoding.h>
00034 
00035 #include "Byte.h"           // synonymous with UInt8 and Char
00036 #include "Int8.h"
00037 #include "Int16.h"
00038 #include "UInt16.h"
00039 #include "Int32.h"
00040 #include "UInt32.h"
00041 
00042 #include "D4Group.h"
00043 #include "D4Enum.h"
00044 #include "D4EnumDefs.h"
00045 #include "D4Attributes.h"
00046 
00047 #include "Float32.h"
00048 #include "Float64.h"
00049 
00050 #include "D4StreamMarshaller.h"
00051 #include "D4StreamUnMarshaller.h"
00052 
00053 #include "Operators.h"
00054 #include "InternalErr.h"
00055 #include "dods-datatypes.h"
00056 #include "dods-limits.h"
00057 #include "util.h"
00058 #include "debug.h"
00059 
00060 using std::cerr;
00061 using std::endl;
00062 
00063 namespace libdap {
00064 
00065 // Private
00066 void D4Enum::m_duplicate(const D4Enum &src)
00067 {
00068     d_buf = src.d_buf;
00069     d_element_type = src.d_element_type;
00070     d_enum_def = src.d_enum_def;
00071 #if 0
00072     // The enum_def is a weak pointer managed by D4Group. We just copy it
00073     // and do not delete it. jhrg 1019/15
00074     d_enum_def = src.d_enum_def == 0 ? 0 : new D4EnumDef(*(src.d_enum_def));
00075 #endif
00076     d_is_signed = src.d_is_signed;
00077 }
00078 
00079 void D4Enum::m_check_value(int64_t v) const
00080 {
00081         switch (d_element_type) {
00082         case dods_byte_c:
00083         case dods_uint8_c:
00084                 if ((uint64_t)v > DODS_UCHAR_MAX || v < 0) {
00085                         ostringstream oss;
00086                         oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
00087                         throw Error(oss.str());
00088                 }
00089                 break;
00090         case dods_uint16_c:
00091                 if ((uint64_t)v > DODS_USHRT_MAX || v < 0) {
00092                         ostringstream oss;
00093                         oss << "The value " << v << " will not fit in an unsigned 16-bit integer. (" << __func__ << ")";
00094                         throw Error(oss.str());
00095                 }
00096                 break;
00097         case dods_uint32_c:
00098                 if ((uint64_t)v > DODS_UINT_MAX || v < 0) {
00099                         ostringstream oss;
00100                         oss << "The value " << v << " will not fit in an unsigned 32-bit integer. (" << __func__ << ")";
00101                         throw Error(oss.str());
00102                 }
00103                 break;
00104         case dods_uint64_c:
00105                 // If 'v' can never be bigger than ULLONG_MAX
00106                 break;
00107 
00108                 case dods_int8_c:
00109                 if (v > DODS_SCHAR_MAX || v < DODS_SCHAR_MIN) {
00110                         ostringstream oss;
00111                         oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
00112                         throw Error(oss.str());
00113                 }
00114 
00115                 break;
00116         case dods_int16_c:
00117                 if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
00118                         ostringstream oss;
00119                         oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
00120                         throw Error(oss.str());
00121                 }
00122                 break;
00123         case dods_int32_c:
00124                 if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
00125                         ostringstream oss;
00126                         oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
00127                         throw Error(oss.str());
00128                 }
00129                 break;
00130         case dods_int64_c:
00131                 // There's no value 'v' can have that won't fit into a 64-bit int.
00132                 break;
00133         default:
00134                 assert(!"illegal type for D4Enum");
00135         }
00136 }
00137 
00138 D4Enum::D4Enum(const string &name, const string &enum_type) :
00139     BaseType(name, dods_enum_c, true /*is_dap4*/), d_buf(0), d_element_type(dods_null_c), d_enum_def(0)
00140 {
00141     d_element_type = get_type(enum_type.c_str());
00142 
00143     if (!is_integer_type(d_element_type)) d_element_type = dods_uint64_c;
00144     set_is_signed(d_element_type);
00145 }
00146 
00147 D4Enum::D4Enum(const string &name, Type type) :
00148     BaseType(name, dods_enum_c, true /*is_dap4*/), d_buf(0), d_element_type(type), d_enum_def(0)
00149 {
00150     if (!is_integer_type(d_element_type)) d_element_type = dods_uint64_c;
00151     set_is_signed(d_element_type);
00152 }
00153 
00154 D4Enum::D4Enum(const string &name, const string &dataset, Type type) :
00155     BaseType(name, dataset, dods_enum_c, true /*is_dap4*/), d_buf(0), d_element_type(type), d_enum_def(0)
00156 {
00157     if (!is_integer_type(d_element_type)) d_element_type = dods_uint64_c;
00158     set_is_signed(d_element_type);
00159 }
00160 
00161 // Explicit instantiation of the template member function 'value(T *)'.
00162 // This is required in order to have the library contain these member
00163 // functions when its own code does not use them. Normally, C++ instantiates
00164 // templates when they are used, and this forces that process so the
00165 // library file contains the various versions of the member function.
00166 template void D4Enum::value<dods_byte>(dods_byte *v) const;
00167 template void D4Enum::value<dods_int16>(dods_int16 *v) const;
00168 template void D4Enum::value<dods_uint16>(dods_uint16 *v) const;
00169 template void D4Enum::value<dods_int32>(dods_int32 *v) const;
00170 template void D4Enum::value<dods_uint32>(dods_uint32 *v) const;
00171 template void D4Enum::value<dods_int64>(dods_int64 *v) const;
00172 template void D4Enum::value<dods_uint64>(dods_uint64 *v) const;
00173 
00174 template void D4Enum::set_value<dods_byte>(dods_byte v, bool check_value);
00175 template void D4Enum::set_value<dods_int16>(dods_int16 v, bool check_value);
00176 template void D4Enum::set_value<dods_uint16>(dods_uint16 v, bool check_value);
00177 template void D4Enum::set_value<dods_int32>(dods_int32 v, bool check_value);
00178 template void D4Enum::set_value<dods_uint32>(dods_uint32 v, bool check_value);
00179 template void D4Enum::set_value<dods_int64>(dods_int64 v, bool check_value);
00180 template void D4Enum::set_value<dods_uint64>(dods_uint64 v, bool check_value);
00181 
00182 void
00183 D4Enum::set_enumeration(D4EnumDef *enum_def) {
00184     d_enum_def = enum_def;
00185     d_element_type = enum_def->type();
00186 }
00187 
00188 void
00189 D4Enum::compute_checksum(Crc32 &checksum)
00190 {
00191         DBG(cerr << __func__ << ": element type: " << ::libdap::type_name(d_element_type) << endl);
00192 
00193     switch (d_element_type) {
00194     case dods_byte_c:
00195     case dods_uint8_c:
00196     case dods_int8_c: {
00197         dods_byte v = static_cast<dods_byte>(d_buf);
00198         checksum.AddData(reinterpret_cast<uint8_t*>(&v), sizeof(uint8_t));
00199         break;
00200     }
00201     case dods_uint16_c:
00202     case dods_int16_c: {
00203         dods_int16 v = static_cast<dods_int16>(d_buf);
00204         checksum.AddData(reinterpret_cast<uint8_t*>(&v), sizeof(uint16_t));
00205         break;
00206     }
00207     case dods_uint32_c:
00208     case dods_int32_c: {
00209         dods_int32 v = static_cast<dods_int32>(d_buf);
00210         checksum.AddData(reinterpret_cast<uint8_t*>(&v), sizeof(uint32_t));
00211         break;
00212     }
00213     case dods_uint64_c:
00214     case dods_int64_c:
00215         checksum.AddData(reinterpret_cast<uint8_t*>(&d_buf), sizeof(uint64_t));
00216         break;
00217 
00218     default:
00219         assert(!"illegal type for D4Enum");
00220     }
00221 }
00222 
00223 void
00224 D4Enum::set_is_signed(Type t)
00225 {
00226         switch (t) {
00227         case dods_byte_c:
00228         case dods_uint8_c:
00229         case dods_uint16_c:
00230         case dods_uint32_c:
00231         case dods_uint64_c:
00232                 d_is_signed = false;
00233                 break;
00234 
00235         case dods_int8_c:
00236         case dods_int16_c:
00237         case dods_int32_c:
00238         case dods_int64_c:
00239                 d_is_signed =  true;
00240                 break;
00241 
00242         default:
00243                 assert(!"illegal type for D4Enum");
00244                 throw InternalErr(__FILE__, __LINE__, "Illegal type");
00245         }
00246 }
00247 
00248 
00261 void
00262 D4Enum::serialize(D4StreamMarshaller &m, DMR &, /*ConstraintEvaluator &,*/ bool)
00263 {
00264     if (!read_p())
00265         read();          // read() throws Error
00266 
00267         switch (d_element_type) {
00268         case dods_byte_c:
00269         case dods_uint8_c:
00270                 m.put_byte(d_buf);
00271                 break;
00272         case dods_uint16_c:
00273                 m.put_uint16(d_buf);
00274                 break;
00275         case dods_uint32_c:
00276                 m.put_uint32(d_buf);
00277                 break;
00278         case dods_uint64_c:
00279                 m.put_uint64(d_buf);
00280                 break;
00281 
00282         case dods_int8_c:
00283                 m.put_int8(d_buf);
00284                 break;
00285         case dods_int16_c:
00286                 m.put_int16(d_buf);
00287                 break;
00288         case dods_int32_c:
00289                 m.put_int32(d_buf);
00290                 break;
00291         case dods_int64_c:
00292                 m.put_int64(d_buf);
00293                 break;
00294         default:
00295                 assert(!"illegal type for D4Enum");
00296         }
00297 }
00298 
00299 void
00300 D4Enum::deserialize(D4StreamUnMarshaller &um, DMR &)
00301 {
00302         switch (d_element_type) {
00303         case dods_byte_c:
00304         case dods_uint8_c: {
00305                 dods_byte v;
00306                 um.get_byte(v);
00307                 d_buf = v;
00308                 break;
00309         }
00310         case dods_uint16_c: {
00311                 dods_uint16 v;
00312                 um.get_uint16(v);
00313                 d_buf = v;
00314                 break;
00315         }
00316         case dods_uint32_c: {
00317                 dods_uint32 v;
00318                 um.get_uint32(v);
00319                 d_buf = v;
00320                 break;
00321         }
00322         case dods_uint64_c: {
00323                 dods_uint64 v;
00324                 um.get_uint64(v);
00325                 d_buf = v;
00326                 break;
00327         }
00328 
00329         case dods_int8_c: {
00330                 dods_int8 v;
00331                 um.get_int8(v);
00332                 d_buf = v;
00333                 break;
00334         }
00335         case dods_int16_c: {
00336                 dods_int16 v;
00337                 um.get_int16(v);
00338                 d_buf = v;
00339                 break;
00340         }
00341         case dods_int32_c: {
00342                 dods_int32 v;
00343                 um.get_int32(v);
00344                 d_buf = v;
00345                 break;
00346         }
00347         case dods_int64_c: {
00348                 dods_int64 v;
00349                 um.get_int64(v);
00350                 d_buf = v;
00351                 break;
00352         }
00353         default:
00354                 assert(!"illegal type for D4Enum");
00355         }
00356 }
00357 
00358 unsigned int D4Enum::val2buf(void *val, bool)
00359 {
00360     if (!val)
00361         throw InternalErr("The incoming pointer does not contain any data.");
00362 
00363     switch (d_element_type) {
00364      case dods_byte_c:
00365      case dods_uint8_c:
00366          d_buf = *(dods_byte*)val;
00367          break;
00368      case dods_uint16_c:
00369          d_buf = *(dods_uint16*)val;
00370          break;
00371      case dods_uint32_c:
00372          d_buf = *(dods_uint32*)val;
00373          break;
00374      case dods_uint64_c:
00375          d_buf = *(dods_uint64*)val;
00376          break;
00377 
00378      case dods_int8_c:
00379          d_buf = *(dods_int8*)val;
00380          break;
00381      case dods_int16_c:
00382          d_buf = *(dods_int16*)val;
00383          break;
00384      case dods_int32_c:
00385          d_buf = *(dods_int32*)val;
00386          break;
00387      case dods_int64_c:
00388          d_buf = *(dods_int64*)val;
00389          break;
00390      default:
00391          assert(!"illegal type for D4Enum");
00392      }
00393 
00394     return width();
00395 }
00396 
00397 unsigned int D4Enum::buf2val(void **val)
00398 {
00399     if (!val)
00400         throw InternalErr("NULL pointer");
00401 
00402     switch (d_element_type) {
00403      case dods_byte_c:
00404      case dods_uint8_c:
00405          if (!*val) *val = new dods_byte;
00406          *(dods_byte *) * val = d_buf;
00407          break;
00408      case dods_uint16_c:
00409          if (!*val) *val = new dods_uint16;
00410          *(dods_uint16 *) * val = d_buf;
00411          break;
00412      case dods_uint32_c:
00413          if (!*val) *val = new dods_uint32;
00414          *(dods_uint32 *) * val = d_buf;
00415          break;
00416      case dods_uint64_c:
00417          if (!*val) *val = new dods_uint64;
00418          *(dods_uint64 *) * val = d_buf;
00419          break;
00420 
00421      case dods_int8_c:
00422          if (!*val) *val = new dods_int8;
00423          *(dods_int8*) * val = d_buf;
00424          break;
00425      case dods_int16_c:
00426          if (!*val) *val = new dods_int16;
00427          *(dods_int16 *) * val = d_buf;
00428          break;
00429      case dods_int32_c:
00430          if (!*val) *val = new dods_int32;
00431          *(dods_int32 *) * val = d_buf;
00432          break;
00433      case dods_int64_c:
00434          if (!*val) *val = new dods_int64;
00435          *(dods_int64 *) * val = d_buf;
00436          break;
00437      default:
00438          assert(!"illegal type for D4Enum");
00439      }
00440 
00441     return width();
00442 }
00443 
00444 void D4Enum::print_val(ostream &out, string space, bool print_decl_p)
00445 {
00446     if (print_decl_p) {
00447         print_decl(out, space, false);
00448         out << " = ";
00449     }
00450 
00451     DBG(cerr << "Enum union value: " << hex << d_buf << dec << endl);
00452 
00453     if (is_signed()) {
00454         int64_t v;
00455         value(&v);
00456         out << v;
00457     }
00458     else {
00459         uint64_t v;
00460         value(&v);
00461         out << v;
00462     }
00463 
00464     if (print_decl_p)
00465         out << ";" << endl;
00466 }
00467 
00474 void
00475 D4Enum::print_xml_writer(XMLWriter &xml, bool constrained)
00476 {
00477     if (constrained && !send_p())
00478         return;
00479 
00480     if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Enum") < 0)
00481         throw InternalErr(__FILE__, __LINE__, "Could not write Enum element");
00482 
00483     if (!name().empty())
00484         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
00485             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
00486 
00487 
00488     string path = d_enum_def->name();
00489     // Not every D4EnumDef is a member of an instance of D4EnumDefs - the D4EnumDefs instance
00490     // holds a reference to the D4Group that holds the Enum definitions.
00491     // TODO Should this be changed - so the EnumDef holds a reference to its parent Group?
00492     if (d_enum_def->parent()) {
00493         // print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
00494         path = static_cast<D4Group*>(d_enum_def->parent()->parent())->FQN() + path;
00495     }
00496     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0)
00497         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
00498 
00499     attributes()->print_dap4(xml);
00500 
00501     if (get_attr_table().get_size() > 0)
00502         get_attr_table().print_xml_writer(xml);
00503 
00504     if (xmlTextWriterEndElement(xml.get_writer()) < 0)
00505         throw InternalErr(__FILE__, __LINE__, "Could not end Enum element");
00506 }
00507 
00508 
00509 bool
00510 D4Enum::ops(BaseType *b, int op)
00511 {
00512     // Get the arg's value.
00513     if (!read_p() && !read())
00514         throw InternalErr(__FILE__, __LINE__, "This value not read!");
00515 
00516     // Get the second arg's value.
00517     if (!b->read_p() && !b->read())
00518         throw InternalErr(__FILE__, __LINE__, "This value not read!");
00519 
00520     switch (b->type()) {
00521         case dods_int8_c:
00522             return Cmp<dods_int64, dods_int8>(op, d_buf, static_cast<Int8*>(b)->value());
00523         case dods_byte_c:
00524             return SUCmp<dods_int64, dods_byte>(op, d_buf, static_cast<Byte*>(b)->value());
00525         case dods_int16_c:
00526             return Cmp<dods_int64, dods_int16>(op, d_buf, static_cast<Int16*>(b)->value());
00527         case dods_uint16_c:
00528             return SUCmp<dods_int64, dods_uint16>(op, d_buf, static_cast<UInt16*>(b)->value());
00529         case dods_int32_c:
00530             return Cmp<dods_int64, dods_int32>(op, d_buf, static_cast<Int32*>(b)->value());
00531         case dods_uint32_c:
00532             return SUCmp<dods_int64, dods_uint32>(op, d_buf, static_cast<UInt32*>(b)->value());
00533 #if 0
00534             // FIXME
00535         case dods_int64_c:
00536             return Cmp<dods_int64, dods_int64>(op, d_buf, static_cast<D4Enum*>(b)->value());
00537         case dods_uint64_c:
00538             return SUCmp<dods_int64, dods_uint64>(op, d_buf, static_cast<D4Enum*>(b)->value());
00539 #endif
00540         case dods_float32_c:
00541             return Cmp<dods_int64, dods_float32>(op, d_buf, static_cast<Float32*>(b)->value());
00542         case dods_float64_c:
00543             return Cmp<dods_int64, dods_float64>(op, d_buf, static_cast<Float64*>(b)->value());
00544         default:
00545             return false;
00546     }
00547 
00548     return false;
00549 }
00550 
00559 void
00560 D4Enum::dump(ostream &strm) const
00561 {
00562     strm << DapIndent::LMarg << "D4Enum::dump - (" << (void *) this << ")" << endl;
00563     DapIndent::Indent();
00564     BaseType::dump(strm);
00565     strm << DapIndent::LMarg << "value: " << d_buf << endl;
00566     DapIndent::UnIndent();
00567 }
00568 
00569 } // namespace libdap
00570