|
Packit |
a4aae4 |
// D4StreamMarshaller.cc
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2012 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <byteswap.h>
|
|
Packit |
a4aae4 |
#include <cassert>
|
|
Packit |
a4aae4 |
#include <cstring>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <iostream>
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
#include <iomanip>
|
|
Packit |
a4aae4 |
#include <limits>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//#define DODS_DEBUG 1
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef HAVE_PTHREAD_H
|
|
Packit |
a4aae4 |
#include <pthread.h>
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "D4StreamMarshaller.h"
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
#include "MarshallerThread.h"
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
#include "XDRUtils.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// We decided to use int64_t to represent sizes of both arrays and strings,
|
|
Packit |
a4aae4 |
// So this code is not used. jhrg 10/4/13
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// From the Google protobuf library
|
|
Packit |
a4aae4 |
inline uint8_t* WriteVarint64ToArrayInline(uint64_t value, uint8_t* target) {
|
|
Packit |
a4aae4 |
// Splitting into 32-bit pieces gives better performance on 32-bit
|
|
Packit |
a4aae4 |
// processors.
|
|
Packit |
a4aae4 |
uint32_t part0 = static_cast<uint32_t>(value );
|
|
Packit |
a4aae4 |
uint32_t part1 = static_cast<uint32_t>(value >> 28);
|
|
Packit |
a4aae4 |
uint32_t part2 = static_cast<uint32_t>(value >> 56);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int size;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Here we can't really optimize for small numbers, since the value is
|
|
Packit |
a4aae4 |
// split into three parts. Checking for numbers < 128, for instance,
|
|
Packit |
a4aae4 |
// would require three comparisons, since you'd have to make sure part1
|
|
Packit |
a4aae4 |
// and part2 are zero. However, if the caller is using 64-bit integers,
|
|
Packit |
a4aae4 |
// it is likely that they expect the numbers to often be very large, so
|
|
Packit |
a4aae4 |
// we probably don't want to optimize for small numbers anyway. Thus,
|
|
Packit |
a4aae4 |
// we end up with a hard coded binary search tree...
|
|
Packit |
a4aae4 |
if (part2 == 0) {
|
|
Packit |
a4aae4 |
if (part1 == 0) {
|
|
Packit |
a4aae4 |
if (part0 < (1 << 14)) {
|
|
Packit |
a4aae4 |
if (part0 < (1 << 7)) {
|
|
Packit |
a4aae4 |
size = 1; goto size1;
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
size = 2; goto size2;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
if (part0 < (1 << 21)) {
|
|
Packit |
a4aae4 |
size = 3; goto size3;
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
size = 4; goto size4;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
if (part1 < (1 << 14)) {
|
|
Packit |
a4aae4 |
if (part1 < (1 << 7)) {
|
|
Packit |
a4aae4 |
size = 5; goto size5;
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
size = 6; goto size6;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
if (part1 < (1 << 21)) {
|
|
Packit |
a4aae4 |
size = 7; goto size7;
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
size = 8; goto size8;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
if (part2 < (1 << 7)) {
|
|
Packit |
a4aae4 |
size = 9; goto size9;
|
|
Packit |
a4aae4 |
} else {
|
|
Packit |
a4aae4 |
size = 10; goto size10;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// GOOGLE_LOG(FATAL) << "Can't get here.";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
size10: target[9] = static_cast<uint8_t>((part2 >> 7) | 0x80);
|
|
Packit |
a4aae4 |
size9 : target[8] = static_cast<uint8_t>((part2 ) | 0x80);
|
|
Packit |
a4aae4 |
size8 : target[7] = static_cast<uint8_t>((part1 >> 21) | 0x80);
|
|
Packit |
a4aae4 |
size7 : target[6] = static_cast<uint8_t>((part1 >> 14) | 0x80);
|
|
Packit |
a4aae4 |
size6 : target[5] = static_cast<uint8_t>((part1 >> 7) | 0x80);
|
|
Packit |
a4aae4 |
size5 : target[4] = static_cast<uint8_t>((part1 ) | 0x80);
|
|
Packit |
a4aae4 |
size4 : target[3] = static_cast<uint8_t>((part0 >> 21) | 0x80);
|
|
Packit |
a4aae4 |
size3 : target[2] = static_cast<uint8_t>((part0 >> 14) | 0x80);
|
|
Packit |
a4aae4 |
size2 : target[1] = static_cast<uint8_t>((part0 >> 7) | 0x80);
|
|
Packit |
a4aae4 |
size1 : target[0] = static_cast<uint8_t>((part0 ) | 0x80);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
target[size-1] &= 0x7F;
|
|
Packit |
a4aae4 |
return target + size;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::m_serialize_reals(char *val, unsigned int num, int width, Type type)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
dods_uint64 size = num * width;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[size];
|
|
Packit |
a4aae4 |
XDR xdr;
|
|
Packit |
a4aae4 |
xdrmem_create(&xdr, &buf[0], size, XDR_ENCODE);
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
if(!xdr_array(&xdr, &val, (unsigned int *)&num, size, width, XDRUtils::xdr_coder(type)))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 array");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xdr_getpos(&xdr) != size)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 array");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If this is a little-endian host, twiddle the bytes
|
|
Packit |
a4aae4 |
static bool twiddle_bytes = !is_host_big_endian();
|
|
Packit |
a4aae4 |
if (twiddle_bytes) {
|
|
Packit |
a4aae4 |
if (width == 4) {
|
|
Packit |
a4aae4 |
dods_float32 *lbuf = reinterpret_cast<dods_float32*>(&buf[0]);
|
|
Packit |
a4aae4 |
while (num--) {
|
|
Packit |
a4aae4 |
dods_int32 *i = reinterpret_cast<dods_int32*>(lbuf++);
|
|
Packit |
a4aae4 |
*i = bswap_32(*i);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else { // width == 8
|
|
Packit |
a4aae4 |
dods_float64 *lbuf = reinterpret_cast<dods_float64*>(&buf[0]);
|
|
Packit |
a4aae4 |
while (num--) {
|
|
Packit |
a4aae4 |
dods_int64 *i = reinterpret_cast<dods_int64*>(lbuf++);
|
|
Packit |
a4aae4 |
*i = bswap_64(*i);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, size);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The child thread will delete buf when it's done
|
|
Packit |
a4aae4 |
xdr_destroy(&xdr;;
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(&buf[0], size);
|
|
Packit |
a4aae4 |
xdr_destroy(&xdr;;
|
|
Packit |
a4aae4 |
delete [] buf;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (...) {
|
|
Packit |
a4aae4 |
xdr_destroy(&xdr;;
|
|
Packit |
a4aae4 |
delete [] buf;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
throw;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Build an instance of D4StreamMarshaller. Bind the C++ stream out to this
|
|
Packit |
a4aae4 |
* instance. If the write_data parameter is true, write the data in addition
|
|
Packit |
a4aae4 |
* to computing and sending the checksum.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param out Write to this stream object.
|
|
Packit |
a4aae4 |
* @param write_data If true, write data values. True by default
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
D4StreamMarshaller::D4StreamMarshaller(ostream &out, bool write_data) :
|
|
Packit |
a4aae4 |
d_out(out), d_write_data(write_data), tm(0)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(sizeof(std::streamsize) >= sizeof(int64_t));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
// XDR is used if the call std::numeric_limits<double>::is_iec559()
|
|
Packit |
a4aae4 |
// returns false indicating that the compiler is not using IEEE 754.
|
|
Packit |
a4aae4 |
// If it is, we just write out the bytes.
|
|
Packit |
a4aae4 |
xdrmem_create(&d_scalar_sink, d_ieee754_buf, sizeof(dods_float64), XDR_ENCODE);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
tm = new MarshallerThread;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This will cause exceptions to be thrown on i/o errors. The exception
|
|
Packit |
a4aae4 |
// will be ostream::failure
|
|
Packit |
a4aae4 |
out.exceptions(ostream::failbit | ostream::badbit);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4StreamMarshaller::~D4StreamMarshaller()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#if USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
xdr_destroy(&d_scalar_sink);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete tm;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Initialize the checksum buffer. This resets the checksum calculation.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::reset_checksum()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_checksum.Reset();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Get the current checksum. It is not possible to continue computing the
|
|
Packit |
a4aae4 |
* checksum once this has been called.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note This method is not intended to be called often or for inserting the
|
|
Packit |
a4aae4 |
* checksum into an I/O stream; see put_checksum(). This is intended for
|
|
Packit |
a4aae4 |
* instrumentation code.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @return The checksum in a string object that always has eight characters.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string D4StreamMarshaller::get_checksum()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
oss.setf(ios::hex, ios::basefield);
|
|
Packit |
a4aae4 |
oss << setfill('0') << setw(8) << d_checksum.GetCrc32();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return oss.str();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Write the checksum
|
|
Packit |
a4aae4 |
* Write the checksum for the data sent since the last call to reset_checksum()
|
|
Packit |
a4aae4 |
* to the I/O stream associated with this marshaller. Use this to send the
|
|
Packit |
a4aae4 |
* checksum, not get_checksum().
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_checksum()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
Crc32::checksum chk = d_checksum.GetCrc32();
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&chk), sizeof(Crc32::checksum));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Update the current CRC 32 checksum value. Calling this with len equal to
|
|
Packit |
a4aae4 |
* zero has no effect on the checksum value.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::checksum_update(const void *data, unsigned long len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_checksum.AddData(reinterpret_cast<const uint8_t*>(data), len);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_byte(dods_byte val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_byte));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
DBG( std::cerr << "put_byte: " << val << std::endl );
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
// make sure that a child thread is not writing to d_out.
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_byte));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_int8(dods_int8 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_int8));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
DBG( std::cerr << "put_int8: " << val << std::endl );
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_int8));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_int16(dods_int16 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_int16));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_int16));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_int32(dods_int32 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_int32));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_int32));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_int64(dods_int64 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_int64));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&val), sizeof(dods_int64));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_float32(dods_float32 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#if !USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
assert(std::numeric_limits<float>::is_iec559);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_float32));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&val), sizeof(dods_float32));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
// This code uses XDR to convert from a local representation to IEEE754;
|
|
Packit |
a4aae4 |
// The extra 'twiddle' operation makes the byte-order correct for this
|
|
Packit |
a4aae4 |
// host should it not be big-endian. Also note the assert() at the
|
|
Packit |
a4aae4 |
// start of the method.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
if (std::numeric_limits<float>::is_iec559 ) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_float32));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (!xdr_setpos(&d_scalar_sink, 0))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float32 variable");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!xdr_float(&d_scalar_sink, &val))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float32 variable");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xdr_getpos(&d_scalar_sink) != sizeof(dods_float32))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float32 variable");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If this is a little-endian host, twiddle the bytes
|
|
Packit |
a4aae4 |
static bool twiddle_bytes = !is_host_big_endian();
|
|
Packit |
a4aae4 |
if (twiddle_bytes) {
|
|
Packit |
a4aae4 |
dods_int32 *i = reinterpret_cast<dods_int32*>(&d_ieee754_buf);
|
|
Packit |
a4aae4 |
*i = bswap_32(*i);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(d_ieee754_buf, sizeof(dods_float32));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_float64(dods_float64 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#if !USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
assert(std::numeric_limits<double>::is_iec559);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_float64));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&val), sizeof(dods_float64));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
// See the comment above in put_float32()
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
if (std::numeric_limits<double>::is_iec559) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_float64));}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (!xdr_setpos(&d_scalar_sink, 0))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 variable");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!xdr_double(&d_scalar_sink, &val))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 variable");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xdr_getpos(&d_scalar_sink) != sizeof(dods_float64))
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error serializing a Float64 variable");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If this is a little-endian host, twiddle the bytes
|
|
Packit |
a4aae4 |
static bool twiddle_bytes = !is_host_big_endian();
|
|
Packit |
a4aae4 |
if (twiddle_bytes) {
|
|
Packit |
a4aae4 |
dods_int64 *i = reinterpret_cast<dods_int64*>(&d_ieee754_buf);
|
|
Packit |
a4aae4 |
*i = bswap_64(*i);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(d_ieee754_buf, sizeof(dods_float64));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_uint16(dods_uint16 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_uint16));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_uint16));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_uint32(dods_uint32 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_uint32));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_uint32));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_uint64(dods_uint64 val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(&val, sizeof(dods_uint64));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<char*>(&val), sizeof(dods_uint64));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Used only for Sequences, where the count must be added to the stream
|
|
Packit |
a4aae4 |
* and then the fields sent using separate calls to methods here. The
|
|
Packit |
a4aae4 |
* methods put_opaque_dap4(), ..., that need counts sent as prefixes to
|
|
Packit |
a4aae4 |
* their data handle it themselves.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param count How many elements follow.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_count(int64_t count)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&count), sizeof(int64_t));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_str(const string &val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
checksum_update(val.c_str(), val.length());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
int64_t len = val.length();
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&len), sizeof(int64_t));
|
|
Packit |
a4aae4 |
d_out.write(val.data(), val.length());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_url(const string &val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
put_str(val);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_opaque_dap4(const char *val, int64_t len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(len >= 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, len);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&len), sizeof(int64_t));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *byte_buf = new char[len];
|
|
Packit |
a4aae4 |
memcpy(byte_buf, val, len);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, byte_buf, len);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(reinterpret_cast<const char*>(&len), sizeof(int64_t));
|
|
Packit |
a4aae4 |
d_out.write(val, len);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Write a fixed size vector
|
|
Packit |
a4aae4 |
* @param val Pointer to the data
|
|
Packit |
a4aae4 |
* @param num Number of bytes to write
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_vector(char *val, int64_t num_bytes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num_bytes >= 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, num_bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[num_bytes];
|
|
Packit |
a4aae4 |
memcpy(buf, val, num_bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, num_bytes);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(val, num_bytes);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_vector(char *val, int64_t num_elem, int elem_size)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num_elem >= 0);
|
|
Packit |
a4aae4 |
assert(elem_size > 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int64_t bytes;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (elem_size) {
|
|
Packit |
a4aae4 |
case 1:
|
|
Packit |
a4aae4 |
assert(!"Don't call this method for bytes, use put_vector(val, bytes) instead");
|
|
Packit |
a4aae4 |
bytes = num_elem;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case 2:
|
|
Packit |
a4aae4 |
// Don't bother testing the sign bit
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0x4000000000000000)); // 0x 40 00 --> 0100 0000
|
|
Packit |
a4aae4 |
bytes = num_elem << 1;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case 4:
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0x6000000000000000)); // 0x 60 00 --> 0110 0000
|
|
Packit |
a4aae4 |
bytes = num_elem << 2;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case 8:
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0x7000000000000000)); // 0111 0000
|
|
Packit |
a4aae4 |
bytes = num_elem << 3;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
bytes = num_elem * elem_size;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[bytes];
|
|
Packit |
a4aae4 |
memcpy(buf, val, bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, bytes);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(val, bytes);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Write a fixed size vector
|
|
Packit |
a4aae4 |
* @note This method and its companion for float64 exists in case we need to
|
|
Packit |
a4aae4 |
* support machine that do not use IEEE754 for their floating point representation.
|
|
Packit |
a4aae4 |
* @param val Pointer to the data
|
|
Packit |
a4aae4 |
* @param num Number of elements
|
|
Packit |
a4aae4 |
* @param width Size of a single element
|
|
Packit |
a4aae4 |
* @param type DAP variable type; used to handle float32 and float64 types correctly
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_vector_float32(char *val, int64_t num_elem)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#if !USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
assert(std::numeric_limits<float>::is_iec559);
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num_elem >= 0);
|
|
Packit |
a4aae4 |
// sizeof() a 32-bit float is 4, so we're going to send 4 * num_elem bytes, so
|
|
Packit |
a4aae4 |
// make sure that doesn't overflow a 63-bit integer (the max positive value in
|
|
Packit |
a4aae4 |
// a signed int64; use 1110 0000 0.. (0xe000 ...) to mask for non-zero bits
|
|
Packit |
a4aae4 |
// to test that num can be multiplied by 4. A
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0xe000000000000000));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
num_elem = num_elem << 2; // num_elem is now the number of bytes
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, num_elem);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[num_elem];
|
|
Packit |
a4aae4 |
memcpy(buf, val, num_elem);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, num_elem);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(val, num_elem);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num_elem >= 0);
|
|
Packit |
a4aae4 |
// sizeof() a 32-bit float is 4, so we're going to send 4 * num_elem bytes, so
|
|
Packit |
a4aae4 |
// make sure that doesn't overflow a 63-bit integer (the max positive value in
|
|
Packit |
a4aae4 |
// a signed int64; use 1110 0000 0.. (0xe000 ...) to mask for non-zero bits
|
|
Packit |
a4aae4 |
// to test that num can be multiplied by 4. A
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0xe000000000000000));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int64_t bytes = num_elem << 2; // num_elem is now the number of bytes
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
if (!std::numeric_limits<float>::is_iec559) {
|
|
Packit |
a4aae4 |
// If not using IEEE 754, use XDR to get it that way.
|
|
Packit |
a4aae4 |
m_serialize_reals(val, num_elem, 4, type);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[bytes];
|
|
Packit |
a4aae4 |
memcpy(buf, val, bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, bytes);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(val, bytes);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Write a fixed size vector of float64s
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param val Pointer to the data
|
|
Packit |
a4aae4 |
* @param num Number of elements
|
|
Packit |
a4aae4 |
* @param width Size of a single element
|
|
Packit |
a4aae4 |
* @param type DAP variable type; used to handle float32 and float64 types correctly
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_vector_float64(char *val, int64_t num_elem)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#if !USE_XDR_FOR_IEEE754_ENCODING
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
assert(std::numeric_limits<double>::is_iec559);
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num_elem >= 0);
|
|
Packit |
a4aae4 |
// See comment above
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0xf000000000000000));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
num_elem = num_elem << 3; // num_elem is now the number of bytes
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, num_elem);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[num_elem];
|
|
Packit |
a4aae4 |
memcpy(buf, val, num_elem);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, num_elem);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(val, num_elem);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num_elem >= 0);
|
|
Packit |
a4aae4 |
// sizeof() a 32-bit float is 4, so we're going to send 4 * num_elem bytes, so
|
|
Packit |
a4aae4 |
// make sure that doesn't overflow a 63-bit integer (the max positive value in
|
|
Packit |
a4aae4 |
// a signed int64; use 1110 0000 0.. (0xe000 ...) to mask for non-zero bits
|
|
Packit |
a4aae4 |
// to test that num can be multiplied by 4. A
|
|
Packit |
a4aae4 |
assert(!(num_elem & 0xe000000000000000));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int64_t bytes = num_elem << 3; // num_elem is now the number of bytes
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
checksum_update(val, bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (d_write_data) {
|
|
Packit |
a4aae4 |
if (!std::numeric_limits<double>::is_iec559) {
|
|
Packit |
a4aae4 |
// If not using IEEE 754, use XDR to get it that way.
|
|
Packit |
a4aae4 |
m_serialize_reals(val, num_elem, 8, type);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
#ifdef USE_POSIX_THREADS
|
|
Packit |
a4aae4 |
Locker lock(tm->get_mutex(), tm->get_cond(), tm->get_child_thread_count());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char *buf = new char[bytes];
|
|
Packit |
a4aae4 |
memcpy(buf, val, bytes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tm->increment_child_thread_count();
|
|
Packit |
a4aae4 |
tm->start_thread(MarshallerThread::write_thread, d_out, buf, bytes);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
d_out.write(val, bytes);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::put_vector_part(char *val, unsigned int num, int width, Type type)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(val);
|
|
Packit |
a4aae4 |
assert(num >= 0);
|
|
Packit |
a4aae4 |
assert(width > 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch(type) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
case dods_char_c:
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
put_vector(val, num);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
put_vector(val, num, width);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_enum_c:
|
|
Packit |
a4aae4 |
if (width == 1)
|
|
Packit |
a4aae4 |
put_vector(val, num);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
put_vector(val, num, width);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
put_vector_float32(val, num);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
put_vector_float32(val, num);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Array of String should not be passed to put_vector.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Array of Array not allowed.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_opaque_c:
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Array of String should not be passed to put_vector.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_grid_c:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Grid is not part of DAP4.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Unknown datatype.");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4StreamMarshaller::dump(ostream &strm) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
strm << DapIndent::LMarg << "D4StreamMarshaller::dump - (" << (void *) this << ")" << endl;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|