libdap++  Updated for version 3.13.3
DAP4StreamUnMarshaller.cc
Go to the documentation of this file.
1 // DAP4StreamUnMarshaller.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 #include "config.h"
28 #include "DAP4StreamUnMarshaller.h"
29 
30 #include <byteswap.h>
31 
32 #include <iostream>
33 #include <iomanip>
34 
35 #include <string>
36 #include <sstream>
37 
38 //#define DODS_DEBUG2 1
39 //#define DODS_DEBUG 1
40 
41 #include "util.h"
42 #include "XDRUtils.h"
43 #include "InternalErr.h"
44 #include "debug.h"
45 
46 namespace libdap {
47 
48 static inline bool is_host_big_endian()
49 {
50 #ifdef COMPUTE_ENDIAN_AT_RUNTIME
51 
52  dods_int16 i = 0x0100;
53  char *c = reinterpret_cast<char*>(&i);
54  return *c;
55 
56 #else
57 
58 #ifdef WORDS_BIGENDIAN
59  return true;
60 #else
61  return false;
62 #endif
63 
64 #endif
65 }
66 
67 DAP4StreamUnMarshaller::DAP4StreamUnMarshaller(istream &in, bool is_stream_big_endian)
68  : d_in( in ), d_buf(0)
69 {
70 #if 0
71  // XDR is used to handle transforming non-ieee754 reals, nothing else.
72  if (!d_buf)
73  // Leaked??? See the XDRStream code
74  d_buf = (char *) malloc(sizeof(dods_float64));
75  if (!d_buf)
76  throw Error("Failed to allocate memory for data serialization.");
77 #endif
78 
79  xdrmem_create(&d_source, &d_buf, sizeof(dods_float64), XDR_DECODE);
80 
81  // This will cause exceptions to be thrown on i/o errors. The exception
82  // will be ostream::failure
83  d_in.exceptions(istream::failbit | istream::badbit);
84 
85  DBG(cerr << "Host is big endian: " << is_host_big_endian() << endl);
86 
87  if ((is_host_big_endian() && is_stream_big_endian)
88  || (!is_host_big_endian() && !is_stream_big_endian))
89  d_twiddle_bytes = false;
90  else
91  d_twiddle_bytes = true;
92 }
93 
95 {
96 }
97 
99 {
100  checksum c;
101  d_in.read(reinterpret_cast<char*>(&c), c_md5_length);
102 
103  return c;
104 }
105 
107 {
108  unsigned char *md = reinterpret_cast<unsigned char*>(&c);
109 
110  ostringstream oss;
111  oss.setf(ios::hex, ios::basefield);
112  for (unsigned int i = 0; i < c_md5_length; ++i) {
113  oss << setfill('0') << setw(2) << (unsigned int)md[i];
114  }
115 
116  return oss.str();
117 }
118 
119 void
121 {
122  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_byte));
123 }
124 
125 void
127 {
128  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int8));
129 }
130 
131 void
133 {
134  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int16));
135  if (d_twiddle_bytes)
136  val = bswap_16(val);
137 }
138 
139 void
141 {
142  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int32));
143  if (d_twiddle_bytes)
144  val = bswap_32(val);
145 }
146 
147 void
149 {
150  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int64));
151  if (d_twiddle_bytes)
152  val = bswap_64(val);
153 }
154 
155 void
157 {
158  if (std::numeric_limits<float>::is_iec559) {
159  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float32));
160  if (d_twiddle_bytes) {
161  dods_int32 *i = reinterpret_cast<dods_int32*>(&val);
162  *i = bswap_32(*i);
163  }
164 
165  }
166  else {
167  xdr_setpos( &d_source, 0);
168  d_in.read(d_buf, sizeof(dods_float32));
169 
170  if (!xdr_float(&d_source, &val))
171  throw Error("Network I/O Error. Could not read float 64 data.");
172  }
173 }
174 
175 void
177 {
178  if (std::numeric_limits<float>::is_iec559) {
179  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float64));
180  if (d_twiddle_bytes) {
181  dods_int64 *i = reinterpret_cast<dods_int64*>(&val);
182  *i = bswap_32(*i);
183  }
184  }
185  else {
186  xdr_setpos( &d_source, 0);
187  d_in.read(d_buf, sizeof(dods_float64));
188 
189  if (!xdr_double(&d_source, &val))
190  throw Error("Network I/O Error. Could not read float 64 data.");
191  }
192 }
193 
194 void
196 {
197  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint16));
198  if (d_twiddle_bytes)
199  val = bswap_16(val);
200 }
201 
202 void
204 {
205  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint32));
206  if (d_twiddle_bytes)
207  val = bswap_32(val);
208 }
209 
210 void
212 {
213  d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint64));
214  if (d_twiddle_bytes)
215  val = bswap_64(val);
216 }
217 
224 {
225  uint8_t b;
226  int count = 0;
227  dods_uint64 result = 0;
228  do {
229  d_in.read(reinterpret_cast<char*>(&b), 1);
230 
231  uint64_t v = (b & 0x7f) << 7 * count;
232  result += v; // is v needed? Does it matter?
233  count++;
234 
235  } while (b & 0x80);
236 
237  return result;
238 }
239 
240 
241 void
243 {
245  vector<char> raw(len+1);
246  d_in.read(&raw[0], len);
247 
248  val.reserve(len);
249  val.assign(&raw[0], len);
250 }
251 
252 void
254 {
255  get_str( val ) ;
256 }
257 
266 void
267 DAP4StreamUnMarshaller::get_opaque( char *val, unsigned int len )
268 {
269  dods_int64 rlen = get_length_prefix();
270  if (len != rlen)
271  throw Error("Expected opaque data of " + long_to_string(len)
272  + " bytes, but got " + long_to_string(rlen) + " instead.");
273 
274  d_in.read(val, len);
275 }
276 
284 void
285 DAP4StreamUnMarshaller::get_opaque( char **val, unsigned int &len )
286 {
287  len = get_length_prefix();
288 
289  *val = new char[len];
290  d_in.read(*val, len);
291 }
292 
293 void
294 DAP4StreamUnMarshaller::get_vector( char *val, unsigned int num )
295 {
296  d_in.read(val, num);
297 }
298 
304 void DAP4StreamUnMarshaller::m_deserialize_reals(char *val, unsigned int num, int width, Type type)
305 {
306  dods_uint64 size = num * width;
307  //char *buf = (char*)malloc(size); This was leaked; xdr_destroy() does not free it.
308  vector<char> buf(size);
309  XDR xdr;
310  xdrmem_create(&xdr, &buf[0], size, XDR_DECODE);
311  try {
312  xdr_setpos(&d_source, 0);
313  d_in.read(&buf[0], size);
314 
315  if(!xdr_array(&xdr, &val, (unsigned int *)&num, size, width, XDRUtils::xdr_coder(type)))
316  throw InternalErr(__FILE__, __LINE__, "Error deserializing a Float64 array");
317 
318  if (xdr_getpos(&xdr) != size)
319  throw InternalErr(__FILE__, __LINE__, "Error deserializing a Float64 array");
320  }
321  catch (...) {
322  xdr_destroy(&xdr);
323  throw;
324  }
325  xdr_destroy(&xdr);
326 }
327 
328 void DAP4StreamUnMarshaller::m_twidle_vector_elements(char *vals, unsigned int num, int width)
329 {
330  switch (width) {
331  case 2: {
332  dods_int16 *local = reinterpret_cast<dods_int16*>(vals);
333  while (num--) {
334  *local = bswap_16(*local);
335  local++;
336  }
337  break;
338  }
339  case 4: {
340  dods_int32 *local = reinterpret_cast<dods_int32*>(vals);;
341  while (num--) {
342  *local = bswap_32(*local);
343  local++;
344  }
345  break;
346  }
347  case 8: {
348  dods_int64 *local = reinterpret_cast<dods_int64*>(vals);;
349  while (num--) {
350  *local = bswap_64(*local);
351  local++;
352  }
353  break;
354  }
355  default:
356  throw InternalErr(__FILE__, __LINE__, "Unrecognized word size.");
357  }
358 }
359 
360 void
361 DAP4StreamUnMarshaller::get_vector( char *val, unsigned int num, int width, Type type )
362 {
363  if (type == dods_float32_c && !std::numeric_limits<float>::is_iec559) {
364  // If not using IEEE 754, use XDR to get it that way.
365  m_deserialize_reals(val, num, 4, type);
366  }
367  else if (type == dods_float64_c && !std::numeric_limits<double>::is_iec559) {
368  m_deserialize_reals(val, num, 8, type);
369  }
370  else {
371  d_in.read(val, num * width);
372  if (d_twiddle_bytes)
373  m_twidle_vector_elements(val, num, width);
374  }
375 }
376 
377 void
378 DAP4StreamUnMarshaller::get_varying_vector( char **val, unsigned int &num )
379 {
380  get_opaque(val, num);
381 }
382 
383 void
384 DAP4StreamUnMarshaller::get_varying_vector( char **val, unsigned int &num, int width, Type type )
385 {
386  num = get_length_prefix();
387 
388  int size = num * width;
389  *val = new char[size];
390 
391  if (type == dods_float32_c && !std::numeric_limits<float>::is_iec559) {
392  m_deserialize_reals(*val, num, 4, type);
393  }
394  else if (type == dods_float64_c && !std::numeric_limits<double>::is_iec559) {
395  m_deserialize_reals(*val, num, 8, type);
396  }
397  else {
398  d_in.read(*val, size);
399  if (d_twiddle_bytes)
400  m_twidle_vector_elements(*val, num, width);
401  }
402 }
403 
404 void
405 DAP4StreamUnMarshaller::dump(ostream &strm) const
406 {
407  strm << DapIndent::LMarg << "DAP4StreamUnMarshaller::dump - ("
408  << (void *)this << ")" << endl ;
409 }
410 
411 } // namespace libdap
412 
virtual void get_uint32(dods_uint32 &val)
DINT32 dods_int32
uint8_t dods_byte
int64_t dods_int64
virtual void get_vector(char **, unsigned int &, Vector &)
virtual void get_uint64(dods_uint64 &val)
virtual void get_int32(dods_int32 &val)
DINT64 dods_int64
Type
Identifies the data type.
Definition: BaseType.h:137
uint16_t dods_uint16
virtual void dump(ostream &strm) const
dump the contents of this object to the specified ostream
virtual void get_byte(dods_byte &val)
uint64_t dods_uint64
virtual void get_int16(dods_int16 &val)
A class for software fault reporting.
Definition: InternalErr.h:64
#define DBG(x)
Definition: debug.h:58
double dods_float64
virtual void get_varying_vector(char **val, unsigned int &num)
virtual void get_int64(dods_int64 &val)
uint32_t dods_uint32
virtual void get_opaque(char *val, unsigned int len)
static const unsigned int c_md5_length
string long_to_string(long val, int base)
Definition: util.cc:773
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:80
int16_t dods_int16
static xdrproc_t xdr_coder(const Type &t)
Returns a function used to encode elements of an array.
Definition: XDRUtils.cc:145
virtual void get_float32(dods_float32 &val)
A class for error processing.
Definition: Error.h:90
DINT16 dods_int16
virtual void get_float64(dods_float64 &val)
virtual void get_uint16(dods_uint16 &val)
virtual void get_int8(dods_int8 &val)
int32_t dods_int32