libdap Updated for version 3.18.1
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
60using std::cerr;
61using std::endl;
62
63namespace libdap {
64
65// Private
66void 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
79void 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
138D4Enum::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
147D4Enum::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
154D4Enum::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.
166template void D4Enum::value<dods_byte>(dods_byte *v) const;
167template void D4Enum::value<dods_int16>(dods_int16 *v) const;
168template void D4Enum::value<dods_uint16>(dods_uint16 *v) const;
169template void D4Enum::value<dods_int32>(dods_int32 *v) const;
170template void D4Enum::value<dods_uint32>(dods_uint32 *v) const;
171template void D4Enum::value<dods_int64>(dods_int64 *v) const;
172template void D4Enum::value<dods_uint64>(dods_uint64 *v) const;
173
174template void D4Enum::set_value<dods_byte>(dods_byte v, bool check_value);
175template void D4Enum::set_value<dods_int16>(dods_int16 v, bool check_value);
176template void D4Enum::set_value<dods_uint16>(dods_uint16 v, bool check_value);
177template void D4Enum::set_value<dods_int32>(dods_int32 v, bool check_value);
178template void D4Enum::set_value<dods_uint32>(dods_uint32 v, bool check_value);
179template void D4Enum::set_value<dods_int64>(dods_int64 v, bool check_value);
180template void D4Enum::set_value<dods_uint64>(dods_uint64 v, bool check_value);
181
182void
183D4Enum::set_enumeration(D4EnumDef *enum_def) {
184 d_enum_def = enum_def;
185 d_element_type = enum_def->type();
186}
187
188void
189D4Enum::compute_checksum(Crc32 &checksum)
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
223void
224D4Enum::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
261void
262D4Enum::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
299void
300D4Enum::deserialize(D4StreamUnMarshaller &um, DMR &)
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
358unsigned 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
397unsigned 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
444void 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
474void
475D4Enum::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
509bool
510D4Enum::ops(BaseType *b, int op)
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
559void
560D4Enum::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
Definition: crc.h:77
void AddData(const uint8_t *pData, const uint32_t length)
Definition: crc.h:98
The basic data type for the DODS DAP types.
Definition: BaseType.h:118
virtual bool read()
Read data into a local buffer.
Definition: BaseType.cc:820
virtual bool read_p()
Has this variable been read?
Definition: BaseType.cc:425
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:310
Holds a single byte.
Definition: Byte.h:61
Holds a DAP4 enumeration.
Definition: D4Enum.h:62
Marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using DAP4's receiv...
Read data from the stream made by D4StreamMarshaller.
Holds a 32-bit floating point value.
Definition: Float32.h:62
Holds a 64-bit (double precision) floating point value.
Definition: Float64.h:61
Holds a 16-bit signed integer value.
Definition: Int16.h:60
Holds a 32-bit signed integer.
Definition: Int32.h:66
Holds an 8-bit signed integer value.
Definition: Int8.h:43
A class for software fault reporting.
Definition: InternalErr.h:65
Holds an unsigned 16-bit integer.
Definition: UInt16.h:58
Holds a 32-bit unsigned integer.
Definition: UInt32.h:60
Type
Identifies the data type.
Definition: Type.h:94
bool is_integer_type(Type t)
Definition: util.cc:902
ObjectType get_type(const string &value)
Definition: mime_util.cc:326