libdap  Updated for version 3.19.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4StreamMarshaller.cc
1 // D4StreamMarshaller.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 #include <cstring>
32 
33 #include <iostream>
34 #include <sstream>
35 #include <iomanip>
36 #include <limits>
37 
38 //#define DODS_DEBUG 1
39 
40 #ifdef HAVE_PTHREAD_H
41 #include <pthread.h>
42 #endif
43 
44 #include "D4StreamMarshaller.h"
45 #ifdef USE_POSIX_THREADS
46 #include "MarshallerThread.h"
47 #endif
48 
49 #if USE_XDR_FOR_IEEE754_ENCODING
50 #include "XDRUtils.h"
51 #include "util.h"
52 #endif
53 
54 #include "debug.h"
55 
56 using namespace std;
57 
58 namespace libdap {
59 
60 #if 0
61 // We decided to use int64_t to represent sizes of both arrays and strings,
62 // So this code is not used. jhrg 10/4/13
63 
64 // From the Google protobuf library
65 inline uint8_t* WriteVarint64ToArrayInline(uint64_t value, uint8_t* target) {
66  // Splitting into 32-bit pieces gives better performance on 32-bit
67  // processors.
68  uint32_t part0 = static_cast<uint32_t>(value );
69  uint32_t part1 = static_cast<uint32_t>(value >> 28);
70  uint32_t part2 = static_cast<uint32_t>(value >> 56);
71 
72  int size;
73 
74  // Here we can't really optimize for small numbers, since the value is
75  // split into three parts. Checking for numbers < 128, for instance,
76  // would require three comparisons, since you'd have to make sure part1
77  // and part2 are zero. However, if the caller is using 64-bit integers,
78  // it is likely that they expect the numbers to often be very large, so
79  // we probably don't want to optimize for small numbers anyway. Thus,
80  // we end up with a hard coded binary search tree...
81  if (part2 == 0) {
82  if (part1 == 0) {
83  if (part0 < (1 << 14)) {
84  if (part0 < (1 << 7)) {
85  size = 1; goto size1;
86  } else {
87  size = 2; goto size2;
88  }
89  } else {
90  if (part0 < (1 << 21)) {
91  size = 3; goto size3;
92  } else {
93  size = 4; goto size4;
94  }
95  }
96  } else {
97  if (part1 < (1 << 14)) {
98  if (part1 < (1 << 7)) {
99  size = 5; goto size5;
100  } else {
101  size = 6; goto size6;
102  }
103  } else {
104  if (part1 < (1 << 21)) {
105  size = 7; goto size7;
106  } else {
107  size = 8; goto size8;
108  }
109  }
110  }
111  } else {
112  if (part2 < (1 << 7)) {
113  size = 9; goto size9;
114  } else {
115  size = 10; goto size10;
116  }
117  }
118 
119  // GOOGLE_LOG(FATAL) << "Can't get here.";
120 
121  size10: target[9] = static_cast<uint8_t>((part2 >> 7) | 0x80);
122  size9 : target[8] = static_cast<uint8_t>((part2 ) | 0x80);
123  size8 : target[7] = static_cast<uint8_t>((part1 >> 21) | 0x80);
124  size7 : target[6] = static_cast<uint8_t>((part1 >> 14) | 0x80);
125  size6 : target[5] = static_cast<uint8_t>((part1 >> 7) | 0x80);
126  size5 : target[4] = static_cast<uint8_t>((part1 ) | 0x80);
127  size4 : target[3] = static_cast<uint8_t>((part0 >> 21) | 0x80);
128  size3 : target[2] = static_cast<uint8_t>((part0 >> 14) | 0x80);
129  size2 : target[1] = static_cast<uint8_t>((part0 >> 7) | 0x80);
130  size1 : target[0] = static_cast<uint8_t>((part0 ) | 0x80);
131 
132  target[size-1] &= 0x7F;
133  return target + size;
134 }
135 #endif
136 
137 #if USE_XDR_FOR_IEEE754_ENCODING
138 void D4StreamMarshaller::m_serialize_reals(char *val, unsigned int num, int width, Type type)
139 {
140  dods_uint64 size = num * width;
141 
142  char *buf = new char[size];
143  XDR xdr;
144  xdrmem_create(&xdr, &buf[0], size, XDR_ENCODE);
145  try {
146  if(!xdr_array(&xdr, &val, (unsigned int *)&num, size, width, XDRUtils::xdr_coder(type)))
147  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 array");
148 
149  if (xdr_getpos(&xdr) != size)
150  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 array");
151 
152  // If this is a little-endian host, twiddle the bytes
153  static bool twiddle_bytes = !is_host_big_endian();
154  if (twiddle_bytes) {
155  if (width == 4) {
156  dods_float32 *lbuf = reinterpret_cast<dods_float32*>(&buf[0]);
157  while (num--) {
158  dods_int32 *i = reinterpret_cast<dods_int32*>(lbuf++);
159  *i = bswap_32(*i);
160  }
161  }
162  else { // width == 8
163  dods_float64 *lbuf = reinterpret_cast<dods_float64*>(&buf[0]);
164  while (num--) {
165  dods_int64 *i = reinterpret_cast<dods_int64*>(lbuf++);
166  *i = bswap_64(*i);
167  }
168  }
169  }
170 #ifdef USE_POSIX_THREADS
171  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
172 
173  tm->increment_child_thread_count();
174  tm->start_thread(MarshallerThread::write_thread, d_out, buf, size);
175 
176  // The child thread will delete buf when it's done
177  xdr_destroy(&xdr);
178 #else
179  d_out.write(&buf[0], size);
180  xdr_destroy(&xdr);
181  delete [] buf;
182 #endif
183  }
184  catch (...) {
185  xdr_destroy(&xdr);
186  delete [] buf;
187 
188  throw;
189  }
190 }
191 #endif
192 
200 D4StreamMarshaller::D4StreamMarshaller(ostream &out, bool write_data) :
201  d_out(out), d_write_data(write_data), tm(0)
202 {
203  assert(sizeof(std::streamsize) >= sizeof(int64_t));
204 
205 #if USE_XDR_FOR_IEEE754_ENCODING
206  // XDR is used if the call std::numeric_limits<double>::is_iec559()
207  // returns false indicating that the compiler is not using IEEE 754.
208  // If it is, we just write out the bytes.
209  xdrmem_create(&d_scalar_sink, d_ieee754_buf, sizeof(dods_float64), XDR_ENCODE);
210 #endif
211 
212 #ifdef USE_POSIX_THREADS
213  tm = new MarshallerThread;
214 #endif
215 
216  // This will cause exceptions to be thrown on i/o errors. The exception
217  // will be ostream::failure
218  out.exceptions(ostream::failbit | ostream::badbit);
219 }
220 
221 D4StreamMarshaller::~D4StreamMarshaller()
222 {
223 #if USE_XDR_FOR_IEEE754_ENCODING
224  xdr_destroy(&d_scalar_sink);
225 #endif
226 
227  delete tm;
228 }
229 
233 {
234  d_checksum.Reset();
235 }
236 
248 {
249  ostringstream oss;
250  oss.setf(ios::hex, ios::basefield);
251  oss << setfill('0') << setw(8) << d_checksum.GetCrc32();
252 
253  return oss.str();
254 }
255 
263 {
264  Crc32::checksum chk = d_checksum.GetCrc32();
265 #ifdef USE_POSIX_THREADS
266  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
267 #endif
268  d_out.write(reinterpret_cast<char*>(&chk), sizeof(Crc32::checksum));
269 }
270 
275 void D4StreamMarshaller::checksum_update(const void *data, unsigned long len)
276 {
277  d_checksum.AddData(reinterpret_cast<const uint8_t*>(data), len);
278 }
279 
280 void D4StreamMarshaller::put_byte(dods_byte val)
281 {
282  checksum_update(&val, sizeof(dods_byte));
283 
284  if (d_write_data) {
285  DBG( std::cerr << "put_byte: " << val << std::endl );
286 #ifdef USE_POSIX_THREADS
287  // make sure that a child thread is not writing to d_out.
288  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
289 #endif
290  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_byte));
291  }
292 }
293 
294 void D4StreamMarshaller::put_int8(dods_int8 val)
295 {
296  checksum_update(&val, sizeof(dods_int8));
297 
298  if (d_write_data) {
299  DBG( std::cerr << "put_int8: " << val << std::endl );
300 #ifdef USE_POSIX_THREADS
301  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
302 #endif
303  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_int8));
304  }
305 }
306 
307 void D4StreamMarshaller::put_int16(dods_int16 val)
308 {
309  checksum_update(&val, sizeof(dods_int16));
310 
311  if (d_write_data) {
312 #ifdef USE_POSIX_THREADS
313  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
314 #endif
315  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_int16));
316  }
317 }
318 
319 void D4StreamMarshaller::put_int32(dods_int32 val)
320 {
321  checksum_update(&val, sizeof(dods_int32));
322 
323  if (d_write_data) {
324 #ifdef USE_POSIX_THREADS
325  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
326 #endif
327  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_int32));
328  }
329 }
330 
331 void D4StreamMarshaller::put_int64(dods_int64 val)
332 {
333  checksum_update(&val, sizeof(dods_int64));
334 
335  if (d_write_data) {
336 #ifdef USE_POSIX_THREADS
337  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
338 #endif
339  d_out.write(reinterpret_cast<const char*>(&val), sizeof(dods_int64));
340  }
341 }
342 
343 void D4StreamMarshaller::put_float32(dods_float32 val)
344 {
345 #if !USE_XDR_FOR_IEEE754_ENCODING
346  assert(std::numeric_limits<float>::is_iec559);
347 
348  checksum_update(&val, sizeof(dods_float32));
349 
350  if (d_write_data) {
351 #ifdef USE_POSIX_THREADS
352  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
353 #endif
354  d_out.write(reinterpret_cast<const char*>(&val), sizeof(dods_float32));
355  }
356 
357 #else
358  // This code uses XDR to convert from a local representation to IEEE754;
359  // The extra 'twiddle' operation makes the byte-order correct for this
360  // host should it not be big-endian. Also note the assert() at the
361  // start of the method.
362 
363  if (d_write_data) {
364  if (std::numeric_limits<float>::is_iec559 ) {
365 #ifdef USE_POSIX_THREADS
366  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
367 #endif
368  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_float32));
369  }
370  else {
371  if (!xdr_setpos(&d_scalar_sink, 0))
372  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float32 variable");
373 
374  if (!xdr_float(&d_scalar_sink, &val))
375  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float32 variable");
376 
377  if (xdr_getpos(&d_scalar_sink) != sizeof(dods_float32))
378  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float32 variable");
379 
380  // If this is a little-endian host, twiddle the bytes
381  static bool twiddle_bytes = !is_host_big_endian();
382  if (twiddle_bytes) {
383  dods_int32 *i = reinterpret_cast<dods_int32*>(&d_ieee754_buf);
384  *i = bswap_32(*i);
385  }
386 #ifdef USE_POSIX_THREADS
387  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
388 #endif
389  d_out.write(d_ieee754_buf, sizeof(dods_float32));
390  }
391  }
392 #endif
393 }
394 
395 void D4StreamMarshaller::put_float64(dods_float64 val)
396 {
397 #if !USE_XDR_FOR_IEEE754_ENCODING
398  assert(std::numeric_limits<double>::is_iec559);
399 
400  checksum_update(&val, sizeof(dods_float64));
401 
402  if (d_write_data) {
403 #ifdef USE_POSIX_THREADS
404  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
405 #endif
406  d_out.write(reinterpret_cast<const char*>(&val), sizeof(dods_float64));
407  }
408 
409 #else
410  // See the comment above in put_float32()
411  if (d_write_data) {
412  if (std::numeric_limits<double>::is_iec559) {
413 #ifdef USE_POSIX_THREADS
414  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
415 #endif
416  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_float64));}
417  }
418  else {
419  if (!xdr_setpos(&d_scalar_sink, 0))
420  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 variable");
421 
422  if (!xdr_double(&d_scalar_sink, &val))
423  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 variable");
424 
425  if (xdr_getpos(&d_scalar_sink) != sizeof(dods_float64))
426  throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 variable");
427 
428  // If this is a little-endian host, twiddle the bytes
429  static bool twiddle_bytes = !is_host_big_endian();
430  if (twiddle_bytes) {
431  dods_int64 *i = reinterpret_cast<dods_int64*>(&d_ieee754_buf);
432  *i = bswap_64(*i);
433  }
434 
435 #ifdef USE_POSIX_THREADS
436  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
437 #endif
438  d_out.write(d_ieee754_buf, sizeof(dods_float64));
439  }
440  }
441 #endif
442 }
443 
444 void D4StreamMarshaller::put_uint16(dods_uint16 val)
445 {
446  checksum_update(&val, sizeof(dods_uint16));
447 
448  if (d_write_data) {
449 #ifdef USE_POSIX_THREADS
450  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
451 #endif
452  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_uint16));
453  }
454 }
455 
456 void D4StreamMarshaller::put_uint32(dods_uint32 val)
457 {
458  checksum_update(&val, sizeof(dods_uint32));
459 
460  if (d_write_data) {
461 #ifdef USE_POSIX_THREADS
462  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
463 #endif
464  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_uint32));
465  }
466 }
467 
468 void D4StreamMarshaller::put_uint64(dods_uint64 val)
469 {
470  checksum_update(&val, sizeof(dods_uint64));
471 
472  if (d_write_data) {
473 #ifdef USE_POSIX_THREADS
474  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
475 #endif
476  d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_uint64));
477  }
478 }
479 
488 void D4StreamMarshaller::put_count(int64_t count)
489 {
490 #ifdef USE_POSIX_THREADS
491  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
492 #endif
493  d_out.write(reinterpret_cast<const char*>(&count), sizeof(int64_t));
494 }
495 
496 void D4StreamMarshaller::put_str(const string &val)
497 {
498  checksum_update(val.c_str(), val.length());
499 
500  if (d_write_data) {
501  int64_t len = val.length();
502 #ifdef USE_POSIX_THREADS
503  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
504 #endif
505  d_out.write(reinterpret_cast<const char*>(&len), sizeof(int64_t));
506  d_out.write(val.data(), val.length());
507  }
508 }
509 
510 void D4StreamMarshaller::put_url(const string &val)
511 {
512  put_str(val);
513 }
514 
515 void D4StreamMarshaller::put_opaque_dap4(const char *val, int64_t len)
516 {
517  assert(val);
518  assert(len >= 0);
519 
520  checksum_update(val, len);
521 
522  if (d_write_data) {
523 #ifdef USE_POSIX_THREADS
524  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
525 
526  d_out.write(reinterpret_cast<const char*>(&len), sizeof(int64_t));
527 
528  char *byte_buf = new char[len];
529  memcpy(byte_buf, val, len);
530 
531  tm->increment_child_thread_count();
532  tm->start_thread(MarshallerThread::write_thread, d_out, byte_buf, len);
533 #else
534  d_out.write(reinterpret_cast<const char*>(&len), sizeof(int64_t));
535  d_out.write(val, len);
536 #endif
537  }
538 }
539 
545 void D4StreamMarshaller::put_vector(char *val, int64_t num_bytes)
546 {
547  assert(val);
548  assert(num_bytes >= 0);
549 
550  checksum_update(val, num_bytes);
551 
552  if (d_write_data) {
553 #ifdef USE_POSIX_THREADS
554  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
555 
556  char *buf = new char[num_bytes];
557  memcpy(buf, val, num_bytes);
558 
559  tm->increment_child_thread_count();
560  tm->start_thread(MarshallerThread::write_thread, d_out, buf, num_bytes);
561 #else
562  d_out.write(val, num_bytes);
563 #endif
564  }
565 }
566 
567 void D4StreamMarshaller::put_vector(char *val, int64_t num_elem, int elem_size)
568 {
569  assert(val);
570  assert(num_elem >= 0);
571  assert(elem_size > 0);
572 
573  int64_t bytes;
574 
575  switch (elem_size) {
576  case 1:
577  assert(!"Don't call this method for bytes, use put_vector(val, bytes) instead");
578  bytes = num_elem;
579  break;
580  case 2:
581  // Don't bother testing the sign bit
582  assert(!(num_elem & 0x4000000000000000)); // 0x 40 00 --> 0100 0000
583  bytes = num_elem << 1;
584  break;
585  case 4:
586  assert(!(num_elem & 0x6000000000000000)); // 0x 60 00 --> 0110 0000
587  bytes = num_elem << 2;
588  break;
589  case 8:
590  assert(!(num_elem & 0x7000000000000000)); // 0111 0000
591  bytes = num_elem << 3;
592  break;
593  default:
594  bytes = num_elem * elem_size;
595  break;
596  }
597 
598  checksum_update(val, bytes);
599 
600  if (d_write_data) {
601 #ifdef USE_POSIX_THREADS
602  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
603 
604  char *buf = new char[bytes];
605  memcpy(buf, val, bytes);
606 
607  tm->increment_child_thread_count();
608  tm->start_thread(MarshallerThread::write_thread, d_out, buf, bytes);
609 #else
610  d_out.write(val, bytes);
611 #endif
612  }
613 }
614 
624 void D4StreamMarshaller::put_vector_float32(char *val, int64_t num_elem)
625 {
626 #if !USE_XDR_FOR_IEEE754_ENCODING
627 
628  assert(std::numeric_limits<float>::is_iec559);
629  assert(val);
630  assert(num_elem >= 0);
631  // sizeof() a 32-bit float is 4, so we're going to send 4 * num_elem bytes, so
632  // make sure that doesn't overflow a 63-bit integer (the max positive value in
633  // a signed int64; use 1110 0000 0.. (0xe000 ...) to mask for non-zero bits
634  // to test that num can be multiplied by 4. A
635  assert(!(num_elem & 0xe000000000000000));
636 
637  num_elem = num_elem << 2; // num_elem is now the number of bytes
638 
639  checksum_update(val, num_elem);
640 
641  if (d_write_data) {
642 #ifdef USE_POSIX_THREADS
643  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
644 
645  char *buf = new char[num_elem];
646  memcpy(buf, val, num_elem);
647 
648  tm->increment_child_thread_count();
649  tm->start_thread(MarshallerThread::write_thread, d_out, buf, num_elem);
650 #else
651  d_out.write(val, num_elem);
652 #endif
653  }
654 
655 #else
656  assert(val);
657  assert(num_elem >= 0);
658  // sizeof() a 32-bit float is 4, so we're going to send 4 * num_elem bytes, so
659  // make sure that doesn't overflow a 63-bit integer (the max positive value in
660  // a signed int64; use 1110 0000 0.. (0xe000 ...) to mask for non-zero bits
661  // to test that num can be multiplied by 4. A
662  assert(!(num_elem & 0xe000000000000000));
663 
664  int64_t bytes = num_elem << 2; // num_elem is now the number of bytes
665 
666  checksum_update(val, bytes);
667 
668  if (d_write_data) {
669  if (!std::numeric_limits<float>::is_iec559) {
670  // If not using IEEE 754, use XDR to get it that way.
671  m_serialize_reals(val, num_elem, 4, type);
672  }
673  else {
674 #ifdef USE_POSIX_THREADS
675  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
676 
677  char *buf = new char[bytes];
678  memcpy(buf, val, bytes);
679 
680  tm->increment_child_thread_count();
681  tm->start_thread(MarshallerThread::write_thread, d_out, buf, bytes);
682 #else
683  d_out.write(val, bytes);
684 #endif
685  }
686  }
687 #endif
688 }
689 
698 void D4StreamMarshaller::put_vector_float64(char *val, int64_t num_elem)
699 {
700 #if !USE_XDR_FOR_IEEE754_ENCODING
701 
702  assert(std::numeric_limits<double>::is_iec559);
703  assert(val);
704  assert(num_elem >= 0);
705  // See comment above
706  assert(!(num_elem & 0xf000000000000000));
707 
708  num_elem = num_elem << 3; // num_elem is now the number of bytes
709 
710  checksum_update(val, num_elem);
711 
712  if (d_write_data) {
713 #ifdef USE_POSIX_THREADS
714  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
715 
716  char *buf = new char[num_elem];
717  memcpy(buf, val, num_elem);
718 
719  tm->increment_child_thread_count();
720  tm->start_thread(MarshallerThread::write_thread, d_out, buf, num_elem);
721 #else
722  d_out.write(val, num_elem);
723 #endif
724  }
725 #else
726  assert(val);
727  assert(num_elem >= 0);
728  // sizeof() a 32-bit float is 4, so we're going to send 4 * num_elem bytes, so
729  // make sure that doesn't overflow a 63-bit integer (the max positive value in
730  // a signed int64; use 1110 0000 0.. (0xe000 ...) to mask for non-zero bits
731  // to test that num can be multiplied by 4. A
732  assert(!(num_elem & 0xe000000000000000));
733 
734  int64_t bytes = num_elem << 3; // num_elem is now the number of bytes
735 
736  checksum_update(val, bytes);
737 
738  if (d_write_data) {
739  if (!std::numeric_limits<double>::is_iec559) {
740  // If not using IEEE 754, use XDR to get it that way.
741  m_serialize_reals(val, num_elem, 8, type);
742  }
743  else {
744 #ifdef USE_POSIX_THREADS
745  Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
746 
747  char *buf = new char[bytes];
748  memcpy(buf, val, bytes);
749 
750  tm->increment_child_thread_count();
751  tm->start_thread(MarshallerThread::write_thread, d_out, buf, bytes);
752 #else
753  d_out.write(val, bytes);
754 #endif
755  }
756  }
757 #endif
758 
759 }
760 
761 void D4StreamMarshaller::put_vector_part(char *val, unsigned int num, int width, Type type)
762 {
763  assert(val);
764  assert(num >= 0);
765  assert(width > 0);
766 
767  switch(type) {
768  case dods_byte_c:
769  case dods_char_c:
770  case dods_int8_c:
771  case dods_uint8_c:
772  put_vector(val, num);
773  break;
774 
775  case dods_int16_c:
776  case dods_uint16_c:
777  case dods_int32_c:
778  case dods_uint32_c:
779  case dods_int64_c:
780  case dods_uint64_c:
781  put_vector(val, num, width);
782  break;
783 
784  case dods_enum_c:
785  if (width == 1)
786  put_vector(val, num);
787  else
788  put_vector(val, num, width);
789  break;
790 
791  case dods_float32_c:
792  put_vector_float32(val, num);
793  break;
794 
795  case dods_float64_c:
796  put_vector_float32(val, num);
797  break;
798 
799  case dods_str_c:
800  case dods_url_c:
801  throw InternalErr(__FILE__, __LINE__, "Array of String should not be passed to put_vector.");
802 
803  case dods_array_c:
804  throw InternalErr(__FILE__, __LINE__, "Array of Array not allowed.");
805 
806  case dods_opaque_c:
807  case dods_structure_c:
808  case dods_sequence_c:
809  throw InternalErr(__FILE__, __LINE__, "Array of String should not be passed to put_vector.");
810 
811  case dods_grid_c:
812  throw InternalErr(__FILE__, __LINE__, "Grid is not part of DAP4.");
813 
814  default:
815  throw InternalErr(__FILE__, __LINE__, "Unknown datatype.");
816  break;
817  }
818 }
819 
820 void D4StreamMarshaller::dump(ostream &strm) const
821 {
822  strm << DapIndent::LMarg << "D4StreamMarshaller::dump - (" << (void *) this << ")" << endl;
823 }
824 
825 } // namespace libdap
826 
STL namespace.
checksum GetCrc32() const
Definition: crc.h:110
Type
Identifies the data type.
Definition: Type.h:94
A class for software fault reporting.
Definition: InternalErr.h:64
void AddData(const uint8_t *pData, const uint32_t length)
Definition: crc.h:98
virtual void checksum_update(const void *data, unsigned long len)
virtual void put_checksum()
Write the checksum Write the checksum for the data sent since the last call to reset_checksum() to th...
bool is_host_big_endian()
Does this host use big-endian byte order?
Definition: util.cc:94
void Reset()
Definition: crc.h:92