libdap  Updated for version 3.18.3
D4Enum.cc
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2013 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 #include "config.h"
27 
28 //#define DODS_DEBUG 1
29 
30 #include <cassert>
31 #include <sstream>
32 
33 #include <libxml/encoding.h>
34 
35 #include "Byte.h" // synonymous with UInt8 and Char
36 #include "Int8.h"
37 #include "Int16.h"
38 #include "UInt16.h"
39 #include "Int32.h"
40 #include "UInt32.h"
41 
42 #include "D4Group.h"
43 #include "D4Enum.h"
44 #include "D4EnumDefs.h"
45 #include "D4Attributes.h"
46 
47 #include "Float32.h"
48 #include "Float64.h"
49 
50 #include "D4StreamMarshaller.h"
51 #include "D4StreamUnMarshaller.h"
52 
53 #include "Operators.h"
54 #include "InternalErr.h"
55 #include "dods-datatypes.h"
56 #include "dods-limits.h"
57 #include "util.h"
58 #include "debug.h"
59 
60 using std::cerr;
61 using std::endl;
62 
63 namespace libdap {
64 
65 // Private
66 void D4Enum::m_duplicate(const D4Enum &src)
67 {
68  d_buf = src.d_buf;
69  d_element_type = src.d_element_type;
70  d_enum_def = src.d_enum_def;
71 #if 0
72  // The enum_def is a weak pointer managed by D4Group. We just copy it
73  // and do not delete it. jhrg 1019/15
74  d_enum_def = src.d_enum_def == 0 ? 0 : new D4EnumDef(*(src.d_enum_def));
75 #endif
76  d_is_signed = src.d_is_signed;
77 }
78 
79 void D4Enum::m_check_value(int64_t v) const
80 {
81  switch (d_element_type) {
82  case dods_byte_c:
83  case dods_uint8_c:
84  if ((uint64_t)v > DODS_UCHAR_MAX || v < 0) {
85  ostringstream oss;
86  oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
87  throw Error(oss.str());
88  }
89  break;
90  case dods_uint16_c:
91  if ((uint64_t)v > DODS_USHRT_MAX || v < 0) {
92  ostringstream oss;
93  oss << "The value " << v << " will not fit in an unsigned 16-bit integer. (" << __func__ << ")";
94  throw Error(oss.str());
95  }
96  break;
97  case dods_uint32_c:
98  if ((uint64_t)v > DODS_UINT_MAX || v < 0) {
99  ostringstream oss;
100  oss << "The value " << v << " will not fit in an unsigned 32-bit integer. (" << __func__ << ")";
101  throw Error(oss.str());
102  }
103  break;
104  case dods_uint64_c:
105  // If 'v' can never be bigger than ULLONG_MAX
106  break;
107 
108  case dods_int8_c:
109  if (v > DODS_SCHAR_MAX || v < DODS_SCHAR_MIN) {
110  ostringstream oss;
111  oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
112  throw Error(oss.str());
113  }
114 
115  break;
116  case dods_int16_c:
117  if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
118  ostringstream oss;
119  oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
120  throw Error(oss.str());
121  }
122  break;
123  case dods_int32_c:
124  if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
125  ostringstream oss;
126  oss << "The value " << v << " will not fit in an unsigned byte. (" << __func__ << ")";
127  throw Error(oss.str());
128  }
129  break;
130  case dods_int64_c:
131  // There's no value 'v' can have that won't fit into a 64-bit int.
132  break;
133  default:
134  assert(!"illegal type for D4Enum");
135  }
136 }
137 
138 D4Enum::D4Enum(const string &name, const string &enum_type) :
139  BaseType(name, dods_enum_c, true /*is_dap4*/), d_buf(0), d_element_type(dods_null_c), d_enum_def(0)
140 {
141  d_element_type = get_type(enum_type.c_str());
142 
143  if (!is_integer_type(d_element_type)) d_element_type = dods_uint64_c;
144  set_is_signed(d_element_type);
145 }
146 
147 D4Enum::D4Enum(const string &name, Type type) :
148  BaseType(name, dods_enum_c, true /*is_dap4*/), d_buf(0), d_element_type(type), d_enum_def(0)
149 {
150  if (!is_integer_type(d_element_type)) d_element_type = dods_uint64_c;
151  set_is_signed(d_element_type);
152 }
153 
154 D4Enum::D4Enum(const string &name, const string &dataset, Type type) :
155  BaseType(name, dataset, dods_enum_c, true /*is_dap4*/), d_buf(0), d_element_type(type), d_enum_def(0)
156 {
157  if (!is_integer_type(d_element_type)) d_element_type = dods_uint64_c;
158  set_is_signed(d_element_type);
159 }
160 
161 // Explicit instantiation of the template member function 'value(T *)'.
162 // This is required in order to have the library contain these member
163 // functions when its own code does not use them. Normally, C++ instantiates
164 // templates when they are used, and this forces that process so the
165 // library file contains the various versions of the member function.
166 template void D4Enum::value<dods_byte>(dods_byte *v) const;
167 template void D4Enum::value<dods_int16>(dods_int16 *v) const;
168 template void D4Enum::value<dods_uint16>(dods_uint16 *v) const;
169 template void D4Enum::value<dods_int32>(dods_int32 *v) const;
170 template void D4Enum::value<dods_uint32>(dods_uint32 *v) const;
171 template void D4Enum::value<dods_int64>(dods_int64 *v) const;
172 template void D4Enum::value<dods_uint64>(dods_uint64 *v) const;
173 
174 template void D4Enum::set_value<dods_byte>(dods_byte v, bool check_value);
175 template void D4Enum::set_value<dods_int16>(dods_int16 v, bool check_value);
176 template void D4Enum::set_value<dods_uint16>(dods_uint16 v, bool check_value);
177 template void D4Enum::set_value<dods_int32>(dods_int32 v, bool check_value);
178 template void D4Enum::set_value<dods_uint32>(dods_uint32 v, bool check_value);
179 template void D4Enum::set_value<dods_int64>(dods_int64 v, bool check_value);
180 template void D4Enum::set_value<dods_uint64>(dods_uint64 v, bool check_value);
181 
182 void
183 D4Enum::set_enumeration(D4EnumDef *enum_def) {
184  d_enum_def = enum_def;
185  d_element_type = enum_def->type();
186 }
187 
188 void
190 {
191  DBG(cerr << __func__ << ": element type: " << ::libdap::type_name(d_element_type) << endl);
192 
193  switch (d_element_type) {
194  case dods_byte_c:
195  case dods_uint8_c:
196  case dods_int8_c: {
197  dods_byte v = static_cast<dods_byte>(d_buf);
198  checksum.AddData(reinterpret_cast<uint8_t*>(&v), sizeof(uint8_t));
199  break;
200  }
201  case dods_uint16_c:
202  case dods_int16_c: {
203  dods_int16 v = static_cast<dods_int16>(d_buf);
204  checksum.AddData(reinterpret_cast<uint8_t*>(&v), sizeof(uint16_t));
205  break;
206  }
207  case dods_uint32_c:
208  case dods_int32_c: {
209  dods_int32 v = static_cast<dods_int32>(d_buf);
210  checksum.AddData(reinterpret_cast<uint8_t*>(&v), sizeof(uint32_t));
211  break;
212  }
213  case dods_uint64_c:
214  case dods_int64_c:
215  checksum.AddData(reinterpret_cast<uint8_t*>(&d_buf), sizeof(uint64_t));
216  break;
217 
218  default:
219  assert(!"illegal type for D4Enum");
220  }
221 }
222 
223 void
224 D4Enum::set_is_signed(Type t)
225 {
226  switch (t) {
227  case dods_byte_c:
228  case dods_uint8_c:
229  case dods_uint16_c:
230  case dods_uint32_c:
231  case dods_uint64_c:
232  d_is_signed = false;
233  break;
234 
235  case dods_int8_c:
236  case dods_int16_c:
237  case dods_int32_c:
238  case dods_int64_c:
239  d_is_signed = true;
240  break;
241 
242  default:
243  assert(!"illegal type for D4Enum");
244  throw InternalErr(__FILE__, __LINE__, "Illegal type");
245  }
246 }
247 
248 
261 void
262 D4Enum::serialize(D4StreamMarshaller &m, DMR &, /*ConstraintEvaluator &,*/ bool)
263 {
264  if (!read_p())
265  read(); // read() throws Error
266 
267  switch (d_element_type) {
268  case dods_byte_c:
269  case dods_uint8_c:
270  m.put_byte(d_buf);
271  break;
272  case dods_uint16_c:
273  m.put_uint16(d_buf);
274  break;
275  case dods_uint32_c:
276  m.put_uint32(d_buf);
277  break;
278  case dods_uint64_c:
279  m.put_uint64(d_buf);
280  break;
281 
282  case dods_int8_c:
283  m.put_int8(d_buf);
284  break;
285  case dods_int16_c:
286  m.put_int16(d_buf);
287  break;
288  case dods_int32_c:
289  m.put_int32(d_buf);
290  break;
291  case dods_int64_c:
292  m.put_int64(d_buf);
293  break;
294  default:
295  assert(!"illegal type for D4Enum");
296  }
297 }
298 
299 void
301 {
302  switch (d_element_type) {
303  case dods_byte_c:
304  case dods_uint8_c: {
305  dods_byte v;
306  um.get_byte(v);
307  d_buf = v;
308  break;
309  }
310  case dods_uint16_c: {
311  dods_uint16 v;
312  um.get_uint16(v);
313  d_buf = v;
314  break;
315  }
316  case dods_uint32_c: {
317  dods_uint32 v;
318  um.get_uint32(v);
319  d_buf = v;
320  break;
321  }
322  case dods_uint64_c: {
323  dods_uint64 v;
324  um.get_uint64(v);
325  d_buf = v;
326  break;
327  }
328 
329  case dods_int8_c: {
330  dods_int8 v;
331  um.get_int8(v);
332  d_buf = v;
333  break;
334  }
335  case dods_int16_c: {
336  dods_int16 v;
337  um.get_int16(v);
338  d_buf = v;
339  break;
340  }
341  case dods_int32_c: {
342  dods_int32 v;
343  um.get_int32(v);
344  d_buf = v;
345  break;
346  }
347  case dods_int64_c: {
348  dods_int64 v;
349  um.get_int64(v);
350  d_buf = v;
351  break;
352  }
353  default:
354  assert(!"illegal type for D4Enum");
355  }
356 }
357 
358 unsigned int D4Enum::val2buf(void *val, bool)
359 {
360  if (!val)
361  throw InternalErr("The incoming pointer does not contain any data.");
362 
363  switch (d_element_type) {
364  case dods_byte_c:
365  case dods_uint8_c:
366  d_buf = *(dods_byte*)val;
367  break;
368  case dods_uint16_c:
369  d_buf = *(dods_uint16*)val;
370  break;
371  case dods_uint32_c:
372  d_buf = *(dods_uint32*)val;
373  break;
374  case dods_uint64_c:
375  d_buf = *(dods_uint64*)val;
376  break;
377 
378  case dods_int8_c:
379  d_buf = *(dods_int8*)val;
380  break;
381  case dods_int16_c:
382  d_buf = *(dods_int16*)val;
383  break;
384  case dods_int32_c:
385  d_buf = *(dods_int32*)val;
386  break;
387  case dods_int64_c:
388  d_buf = *(dods_int64*)val;
389  break;
390  default:
391  assert(!"illegal type for D4Enum");
392  }
393 
394  return width();
395 }
396 
397 unsigned int D4Enum::buf2val(void **val)
398 {
399  if (!val)
400  throw InternalErr("NULL pointer");
401 
402  switch (d_element_type) {
403  case dods_byte_c:
404  case dods_uint8_c:
405  if (!*val) *val = new dods_byte;
406  *(dods_byte *) * val = d_buf;
407  break;
408  case dods_uint16_c:
409  if (!*val) *val = new dods_uint16;
410  *(dods_uint16 *) * val = d_buf;
411  break;
412  case dods_uint32_c:
413  if (!*val) *val = new dods_uint32;
414  *(dods_uint32 *) * val = d_buf;
415  break;
416  case dods_uint64_c:
417  if (!*val) *val = new dods_uint64;
418  *(dods_uint64 *) * val = d_buf;
419  break;
420 
421  case dods_int8_c:
422  if (!*val) *val = new dods_int8;
423  *(dods_int8*) * val = d_buf;
424  break;
425  case dods_int16_c:
426  if (!*val) *val = new dods_int16;
427  *(dods_int16 *) * val = d_buf;
428  break;
429  case dods_int32_c:
430  if (!*val) *val = new dods_int32;
431  *(dods_int32 *) * val = d_buf;
432  break;
433  case dods_int64_c:
434  if (!*val) *val = new dods_int64;
435  *(dods_int64 *) * val = d_buf;
436  break;
437  default:
438  assert(!"illegal type for D4Enum");
439  }
440 
441  return width();
442 }
443 
444 void D4Enum::print_val(ostream &out, string space, bool print_decl_p)
445 {
446  if (print_decl_p) {
447  print_decl(out, space, false);
448  out << " = ";
449  }
450 
451  DBG(cerr << "Enum union value: " << hex << d_buf << dec << endl);
452 
453  if (is_signed()) {
454  int64_t v;
455  value(&v);
456  out << v;
457  }
458  else {
459  uint64_t v;
460  value(&v);
461  out << v;
462  }
463 
464  if (print_decl_p)
465  out << ";" << endl;
466 }
467 
474 void
475 D4Enum::print_xml_writer(XMLWriter &xml, bool constrained)
476 {
477  if (constrained && !send_p())
478  return;
479 
480  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Enum") < 0)
481  throw InternalErr(__FILE__, __LINE__, "Could not write Enum element");
482 
483  if (!name().empty())
484  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
485  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
486 
487 
488  string path = d_enum_def->name();
489  // Not every D4EnumDef is a member of an instance of D4EnumDefs - the D4EnumDefs instance
490  // holds a reference to the D4Group that holds the Enum definitions.
491  // TODO Should this be changed - so the EnumDef holds a reference to its parent Group?
492  if (d_enum_def->parent()) {
493  // print the FQN for the enum def; D4Group::FQN() includes the trailing '/'
494  path = static_cast<D4Group*>(d_enum_def->parent()->parent())->FQN() + path;
495  }
496  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "enum", (const xmlChar*)path.c_str()) < 0)
497  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for enum");
498 
499  attributes()->print_dap4(xml);
500 
501  if (get_attr_table().get_size() > 0)
502  get_attr_table().print_xml_writer(xml);
503 
504  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
505  throw InternalErr(__FILE__, __LINE__, "Could not end Enum element");
506 }
507 
508 
509 bool
511 {
512  // Get the arg's value.
513  if (!read_p() && !read())
514  throw InternalErr(__FILE__, __LINE__, "This value not read!");
515 
516  // Get the second arg's value.
517  if (!b->read_p() && !b->read())
518  throw InternalErr(__FILE__, __LINE__, "This value not read!");
519 
520  switch (b->type()) {
521  case dods_int8_c:
522  return Cmp<dods_int64, dods_int8>(op, d_buf, static_cast<Int8*>(b)->value());
523  case dods_byte_c:
524  return SUCmp<dods_int64, dods_byte>(op, d_buf, static_cast<Byte*>(b)->value());
525  case dods_int16_c:
526  return Cmp<dods_int64, dods_int16>(op, d_buf, static_cast<Int16*>(b)->value());
527  case dods_uint16_c:
528  return SUCmp<dods_int64, dods_uint16>(op, d_buf, static_cast<UInt16*>(b)->value());
529  case dods_int32_c:
530  return Cmp<dods_int64, dods_int32>(op, d_buf, static_cast<Int32*>(b)->value());
531  case dods_uint32_c:
532  return SUCmp<dods_int64, dods_uint32>(op, d_buf, static_cast<UInt32*>(b)->value());
533 #if 0
534  // FIXME
535  case dods_int64_c:
536  return Cmp<dods_int64, dods_int64>(op, d_buf, static_cast<D4Enum*>(b)->value());
537  case dods_uint64_c:
538  return SUCmp<dods_int64, dods_uint64>(op, d_buf, static_cast<D4Enum*>(b)->value());
539 #endif
540  case dods_float32_c:
541  return Cmp<dods_int64, dods_float32>(op, d_buf, static_cast<Float32*>(b)->value());
542  case dods_float64_c:
543  return Cmp<dods_int64, dods_float64>(op, d_buf, static_cast<Float64*>(b)->value());
544  default:
545  return false;
546  }
547 
548  return false;
549 }
550 
559 void
560 D4Enum::dump(ostream &strm) const
561 {
562  strm << DapIndent::LMarg << "D4Enum::dump - (" << (void *) this << ")" << endl;
563  DapIndent::Indent();
564  BaseType::dump(strm);
565  strm << DapIndent::LMarg << "value: " << d_buf << endl;
566  DapIndent::UnIndent();
567 }
568 
569 } // namespace libdap
570 
virtual bool read()
Read data into a local buffer.
Definition: BaseType.cc:820
Holds an 8-bit signed integer value.
Definition: Int8.h:42
virtual bool read_p()
Has this variable been read?
Definition: BaseType.cc:425
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:265
virtual void dump(ostream &strm) const
dumps information about this object
Definition: BaseType.cc:236
unsigned int val2buf(void *, bool)
Loads class data.
Definition: D4Enum.cc:358
Read data from the stream made by D4StreamMarshaller.
Holds an unsigned 16-bit integer.
Definition: UInt16.h:57
Definition: crc.h:76
BaseType(const string &n, const Type &t, bool is_dap4=false)
The BaseType constructor.
Definition: BaseType.cc:125
virtual void print_val(ostream &out, string space="", bool print_decl_p=true)
Prints the value of the variable.
Definition: D4Enum.cc:444
Type
Identifies the data type.
Definition: Type.h:94
Holds a 32-bit floating point value.
Definition: Float32.h:61
A class for software fault reporting.
Definition: InternalErr.h:64
Holds a DAP4 enumeration.
Definition: D4Enum.h:61
virtual void serialize(D4StreamMarshaller &m, DMR &dmr, bool filter=false)
Serialize a D4Enum Use the (integer) data type associated with an Enumeration definition to serialize...
Definition: D4Enum.cc:262
Marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using DAP4&#39;s receiv...
Holds a 16-bit signed integer value.
Definition: Int16.h:59
virtual void dump(ostream &strm) const
dumps information about this object
Definition: D4Enum.cc:560
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:310
ObjectType get_type(const string &value)
Definition: mime_util.cc:326
virtual void compute_checksum(Crc32 &checksum)
include the data for this variable in the checksum DAP4 includes a checksum with every data response...
Definition: D4Enum.cc:189
void AddData(const uint8_t *pData, const uint32_t length)
Definition: crc.h:98
virtual void deserialize(D4StreamUnMarshaller &um, DMR &dmr)
Definition: D4Enum.cc:300
virtual void print_xml_writer(XMLWriter &xml, bool constrained)
Definition: D4Enum.cc:475
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
Holds a 64-bit (double precision) floating point value.
Definition: Float64.h:60
Holds a single byte.
Definition: Byte.h:60
virtual bool ops(BaseType *b, int op)
Evaluate relational operators.
Definition: D4Enum.cc:510
Holds a 32-bit unsigned integer.
Definition: UInt32.h:59
string type_name(Type t)
Definition: util.cc:759
unsigned int buf2val(void **)
Reads the class data.
Definition: D4Enum.cc:397
Holds a 32-bit signed integer.
Definition: Int32.h:65
bool is_integer_type(Type t)
Definition: util.cc:905