libdap  Updated for version 3.20.6
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4StreamUnMarshaller.cc
1 // D4StreamUnMarshaller.cc
2 
3 // -*- mode: c++; c-basic-offset:4 -*-
4 
5 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
6 // Access Protocol.
7 
8 // Copyright (c) 2012 OPeNDAP, Inc.
9 // Author: James Gallagher <jgallagher@opendap.org>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 #include "config.h"
28 
29 #include <byteswap.h>
30 #include <cassert>
31 
32 #include <iostream>
33 #include <iomanip>
34 #include <limits>
35 #include <string>
36 #include <sstream>
37 
38 //#define DODS_DEBUG2 1
39 //#define DODS_DEBUG 1
40 
41 #include "util.h"
42 #include "InternalErr.h"
43 #include "D4StreamUnMarshaller.h"
44 #include "debug.h"
45 #include "DapIndent.h"
46 
47 namespace libdap {
48 
59 D4StreamUnMarshaller::D4StreamUnMarshaller(istream &in, bool twiddle_bytes) : d_in( in ), d_twiddle_bytes(twiddle_bytes)
60 {
61  assert(sizeof(std::streamsize) >= sizeof(int64_t));
62 
63 #if USE_XDR_FOR_IEEE754_ENCODING
64  // XDR is used to handle transforming non-ieee754 reals, nothing else.
65  xdrmem_create(&d_source, d_buf, sizeof(dods_float64), XDR_DECODE);
66 #endif
67 
68  // This will cause exceptions to be thrown on i/o errors. The exception
69  // will be ostream::failure
70  d_in.exceptions(istream::failbit | istream::badbit);
71 
72 }
73 
80 D4StreamUnMarshaller::D4StreamUnMarshaller(istream &in) : d_in( in ), d_twiddle_bytes(false)
81 {
82  assert(sizeof(std::streamsize) >= sizeof(int64_t));
83 
84 #if USE_XDR_FOR_IEEE754_ENCODING
85  // XDR is used to handle transforming non-ieee754 reals, nothing else.
86  xdrmem_create(&d_source, d_buf, sizeof(dods_float64), XDR_DECODE);
87 #endif
88 
89  // This will cause exceptions to be thrown on i/o errors. The exception
90  // will be ostream::failure
91  d_in.exceptions(istream::failbit | istream::badbit);
92 }
93 
94 D4StreamUnMarshaller::~D4StreamUnMarshaller( )
95 {
96 #if USE_XDR_FOR_IEEE754_ENCODING
97  xdr_destroy(&d_source);
98 #endif
99 }
100 
101 Crc32::checksum D4StreamUnMarshaller::get_checksum()
102 {
103  Crc32::checksum c;
104  d_in.read(reinterpret_cast<char*>(&c), sizeof(Crc32::checksum));
105 
106  return c;
107 }
108 
109 string D4StreamUnMarshaller::get_checksum_str()
110 {
111  ostringstream oss;
112  oss.setf(ios::hex, ios::basefield);
113  oss << setfill('0') << setw(8) << get_checksum();
114 
115  return oss.str();
116 }
117 
118 void
119 D4StreamUnMarshaller::get_byte( dods_byte &val )
120 {
121  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_byte));
122 }
123 
124 void
125 D4StreamUnMarshaller::get_int8( dods_int8 &val )
126 {
127  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int8));
128 }
129 
130 void
131 D4StreamUnMarshaller::get_int16( dods_int16 &val )
132 {
133  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int16));
134  if (d_twiddle_bytes)
135  val = bswap_16(val);
136 }
137 
138 void
139 D4StreamUnMarshaller::get_int32( dods_int32 &val )
140 {
141  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int32));
142  if (d_twiddle_bytes)
143  val = bswap_32(val);
144 }
145 
146 void
147 D4StreamUnMarshaller::get_int64( dods_int64 &val )
148 {
149  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int64));
150  if (d_twiddle_bytes)
151  val = bswap_64(val);
152 }
153 
154 void
155 D4StreamUnMarshaller::get_float32( dods_float32 &val )
156 {
157 #if !USE_XDR_FOR_IEEE754_ENCODING
158  assert(std::numeric_limits<float>::is_iec559);
159 
160  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float32));
161  if (d_twiddle_bytes) {
162  dods_int32 *i = reinterpret_cast<dods_int32*>(&val);
163  *i = bswap_32(*i);
164  }
165 
166 #else
167  if (std::numeric_limits<float>::is_iec559) {
168  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float32));
169  if (d_twiddle_bytes) {
170  dods_int32 *i = reinterpret_cast<dods_int32*>(&val);
171  *i = bswap_32(*i);
172  }
173 
174  }
175  else {
176  xdr_setpos( &d_source, 0);
177  d_in.read(d_buf, sizeof(dods_float32));
178 
179  if (!xdr_float(&d_source, &val))
180  throw Error("Network I/O Error. Could not read float 64 data.");
181  }
182 #endif
183 }
184 
185 void
186 D4StreamUnMarshaller::get_float64( dods_float64 &val )
187 {
188 #if !USE_XDR_FOR_IEEE754_ENCODING
189  assert(std::numeric_limits<double>::is_iec559);
190 
191  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float64));
192  if (d_twiddle_bytes) {
193  dods_int64 *i = reinterpret_cast<dods_int64*>(&val);
194  *i = bswap_64(*i);
195  }
196 
197 #else
198  if (std::numeric_limits<float>::is_iec559) {
199  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float64));
200  if (d_twiddle_bytes) {
201  dods_int64 *i = reinterpret_cast<dods_int64*>(&val);
202  *i = bswap_64(*i);
203  }
204  }
205  else {
206  xdr_setpos( &d_source, 0);
207  d_in.read(d_buf, sizeof(dods_float64));
208 
209  if (!xdr_double(&d_source, &val))
210  throw Error("Network I/O Error. Could not read float 64 data.");
211  }
212 #endif
213 }
214 
215 void
216 D4StreamUnMarshaller::get_uint16( dods_uint16 &val )
217 {
218  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint16));
219  if (d_twiddle_bytes)
220  val = bswap_16(val);
221 }
222 
223 void
224 D4StreamUnMarshaller::get_uint32( dods_uint32 &val )
225 {
226  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint32));
227  if (d_twiddle_bytes)
228  val = bswap_32(val);
229 }
230 
231 void
232 D4StreamUnMarshaller::get_uint64( dods_uint64 &val )
233 {
234  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint64));
235  if (d_twiddle_bytes)
236  val = bswap_64(val);
237 }
238 
239 void
240 D4StreamUnMarshaller::get_str( string &val )
241 {
242  int64_t len;
243  d_in.read(reinterpret_cast<char*>(&len), sizeof(int64_t));
244 
245  val.resize(len);
246  d_in.read(&val[0], len);
247 }
248 
249 void
250 D4StreamUnMarshaller::get_url( string &val )
251 {
252  get_str( val ) ;
253 }
254 
263 int64_t
265 {
266  int64_t count;
267  d_in.read(reinterpret_cast<char*>(&count), sizeof(count));
268  return count;
269 }
270 
278 void
279 D4StreamUnMarshaller::get_opaque_dap4( char **val, int64_t &len )
280 {
281  //len = get_length_prefix();
282  d_in.read(reinterpret_cast<char*>(&len), sizeof(len));
283 
284  *val = new char[len];
285  d_in.read(*val, len);
286 }
287 
288 void
289 D4StreamUnMarshaller::get_opaque_dap4( vector<uint8_t> &val )
290 {
291  //len = get_length_prefix();
292  int64_t len;
293  d_in.read(reinterpret_cast<char*>(&len), sizeof(len));
294 
295  val.resize(len);
296  d_in.read(reinterpret_cast<char*>(&val[0]), len);
297 }
298 
299 void
300 D4StreamUnMarshaller::get_vector( char *val, int64_t bytes )
301 {
302  d_in.read(val, bytes);
303 }
304 
305 #if USE_XDR_FOR_IEEE754_ENCODING
306 void D4StreamUnMarshaller::m_deserialize_reals(char *val, int64_t num, int width, Type type)
307 {
308  int64_t size = num * width;
309  // char *buf = (char*)malloc(size); jhrg 7/23/13
310  vector<char> buf(size);
311  XDR xdr;
312  xdrmem_create(&xdr, &buf[0], size, XDR_DECODE);
313  try {
314  xdr_setpos(&d_source, 0);
315  d_in.read(&buf[0], size);
316 
317  if(!xdr_array(&xdr, &val, (unsigned int *)&num, size, width, XDRUtils::xdr_coder(type)))
318  throw InternalErr(__FILE__, __LINE__, "Error deserializing a Float64 array");
319 
320  if (xdr_getpos(&xdr) != size)
321  throw InternalErr(__FILE__, __LINE__, "Error deserializing a Float64 array");
322  }
323  catch (...) {
324  xdr_destroy(&xdr);
325  throw;
326  }
327  xdr_destroy(&xdr);
328 }
329 #endif
330 
331 void D4StreamUnMarshaller::m_twidle_vector_elements(char *vals, int64_t num, int width)
332 {
333  switch (width) {
334  case 2: {
335  dods_int16 *local = reinterpret_cast<dods_int16*>(vals);
336  while (num--) {
337  *local = bswap_16(*local);
338  local++;
339  }
340  break;
341  }
342  case 4: {
343  dods_int32 *local = reinterpret_cast<dods_int32*>(vals);;
344  while (num--) {
345  *local = bswap_32(*local);
346  local++;
347  }
348  break;
349  }
350  case 8: {
351  dods_int64 *local = reinterpret_cast<dods_int64*>(vals);;
352  while (num--) {
353  *local = bswap_64(*local);
354  local++;
355  }
356  break;
357  }
358  default:
359  throw InternalErr(__FILE__, __LINE__, "Unrecognized word size.");
360  }
361 }
362 
363 void
364 D4StreamUnMarshaller::get_vector(char *val, int64_t num_elem, int elem_size)
365 {
366  assert(std::numeric_limits<float>::is_iec559);
367  assert(std::numeric_limits<double>::is_iec559);
368  assert(val);
369  assert(num_elem >= 0);
370  assert(elem_size > 0);
371 
372  int64_t bytes;
373 
374  switch (elem_size) {
375  case 1:
376  assert(!"Don't call this method for bytes, use put_vector(val, bytes) instead");
377  bytes = num_elem;
378  break;
379  case 2:
380  // Don't bother testing the sign bit
381  assert(!(num_elem & 0x4000000000000000)); // 0x 40 00 --> 0100 0000
382  bytes = num_elem << 1;
383  break;
384  case 4:
385  assert(!(num_elem & 0x6000000000000000)); // 0x 60 00 --> 0110 0000
386  bytes = num_elem << 2;
387  break;
388  case 8:
389  assert(!(num_elem & 0x7000000000000000)); // 0111 0000
390  bytes = num_elem << 3;
391  break;
392  default:
393  bytes = num_elem * elem_size;
394  break;
395  }
396 
397  d_in.read(val, bytes);
398 
399  if (d_twiddle_bytes)
400  m_twidle_vector_elements(val, num_elem, elem_size);
401 }
402 
403 void
404 D4StreamUnMarshaller::get_vector_float32(char *val, int64_t num_elem)
405 {
406 #if !USE_XDR_FOR_IEEE754_ENCODING
407  assert(std::numeric_limits<float>::is_iec559);
408  assert(val);
409  assert(num_elem >= 0);
410  assert(!(num_elem & 0x6000000000000000)); // 0x 60 00 --> 0110 0000
411 
412  int64_t bytes = num_elem << 2;
413 
414  d_in.read(val, bytes);
415 
416  if (d_twiddle_bytes)
417  m_twidle_vector_elements(val, num_elem, sizeof(dods_float32));
418 
419 #else
420  if (type == dods_float32_c && !std::numeric_limits<float>::is_iec559) {
421  // If not using IEEE 754, use XDR to get it that way.
422  m_deserialize_reals(val, num, 4, type);
423  }
424  else if (type == dods_float64_c && !std::numeric_limits<double>::is_iec559) {
425  m_deserialize_reals(val, num, 8, type);
426  }
427  else {
428  d_in.read(val, num * width);
429  if (d_twiddle_bytes)
430  m_twidle_vector_elements(val, num, width);
431  }
432 #endif
433 }
434 
435 void
436 D4StreamUnMarshaller::get_vector_float64(char *val, int64_t num_elem)
437 {
438 #if !USE_XDR_FOR_IEEE754_ENCODING
439  assert(std::numeric_limits<float>::is_iec559);
440  assert(val);
441  assert(num_elem >= 0);
442  assert(!(num_elem & 0x7000000000000000)); // 0x 70 00 --> 0111 0000
443 
444  int64_t bytes = num_elem << 3;
445 
446  d_in.read(val, bytes);
447 
448  if (d_twiddle_bytes)
449  m_twidle_vector_elements(val, num_elem, sizeof(dods_float64));
450 
451 #else
452  if (type == dods_float32_c && !std::numeric_limits<float>::is_iec559) {
453  // If not using IEEE 754, use XDR to get it that way.
454  m_deserialize_reals(val, num, 4, type);
455  }
456  else if (type == dods_float64_c && !std::numeric_limits<double>::is_iec559) {
457  m_deserialize_reals(val, num, 8, type);
458  }
459  else {
460  d_in.read(val, num * width);
461  if (d_twiddle_bytes)
462  m_twidle_vector_elements(val, num, width);
463  }
464 #endif
465 }
466 
467 void
468 D4StreamUnMarshaller::dump(ostream &strm) const
469 {
470  strm << DapIndent::LMarg << "D4StreamUnMarshaller::dump - ("
471  << (void *)this << ")" << endl ;
472 }
473 
474 } // namespace libdap
475 
virtual void dump(ostream &strm) const
dump the contents of this object to the specified ostream
Type
Identifies the data type.
Definition: Type.h:94
top level DAP object to house generic methods
Definition: AISConnect.cc:30
virtual void get_opaque_dap4(char **val, int64_t &len)
A class for software fault reporting.
Definition: InternalErr.h:64
static xdrproc_t xdr_coder(const Type &t)
Returns a function used to encode elements of an array.
Definition: XDRUtils.cc:145
A class for error processing.
Definition: Error.h:92