libdap
Updated for version 3.17.0
|
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