libdap  Updated for version 3.17.0
D4StreamUnMarshaller.cc
00001 // D4StreamUnMarshaller.cc
00002 
00003 // -*- mode: c++; c-basic-offset:4 -*-
00004 
00005 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00006 // Access Protocol.
00007 
00008 // Copyright (c) 2012 OPeNDAP, Inc.
00009 // Author: James Gallagher <jgallagher@opendap.org>
00010 //
00011 // This library is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU Lesser General Public
00013 // License as published by the Free Software Foundation; either
00014 // version 2.1 of the License, or (at your option) any later version.
00015 //
00016 // This library is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 //
00025 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00026 
00027 #include "config.h"
00028 
00029 #include <byteswap.h>
00030 #include <cassert>
00031 
00032 #include <iostream>
00033 #include <iomanip>
00034 #include <limits>
00035 #include <string>
00036 #include <sstream>
00037 
00038 //#define DODS_DEBUG2 1
00039 //#define DODS_DEBUG 1
00040 
00041 #include "util.h"
00042 //#include "XDRUtils.h"
00043 #include "InternalErr.h"
00044 #include "D4StreamUnMarshaller.h"
00045 #include "debug.h"
00046 
00047 namespace libdap {
00048 
00059 D4StreamUnMarshaller::D4StreamUnMarshaller(istream &in, bool twiddle_bytes) : d_in( in ), d_twiddle_bytes(twiddle_bytes)
00060 {
00061         assert(sizeof(std::streamsize) >= sizeof(int64_t));
00062 
00063 #if USE_XDR_FOR_IEEE754_ENCODING
00064         // XDR is used to handle transforming non-ieee754 reals, nothing else.
00065     xdrmem_create(&d_source, d_buf, sizeof(dods_float64), XDR_DECODE);
00066 #endif
00067 
00068     // This will cause exceptions to be thrown on i/o errors. The exception
00069     // will be ostream::failure
00070     d_in.exceptions(istream::failbit | istream::badbit);
00071 
00072 }
00073 
00080 D4StreamUnMarshaller::D4StreamUnMarshaller(istream &in) : d_in( in ), d_twiddle_bytes(false)
00081 {
00082         assert(sizeof(std::streamsize) >= sizeof(int64_t));
00083 
00084 #if USE_XDR_FOR_IEEE754_ENCODING
00085     // XDR is used to handle transforming non-ieee754 reals, nothing else.
00086     xdrmem_create(&d_source, d_buf, sizeof(dods_float64), XDR_DECODE);
00087 #endif
00088 
00089     // This will cause exceptions to be thrown on i/o errors. The exception
00090     // will be ostream::failure
00091     d_in.exceptions(istream::failbit | istream::badbit);
00092 }
00093 
00094 D4StreamUnMarshaller::~D4StreamUnMarshaller( )
00095 {
00096 #if USE_XDR_FOR_IEEE754_ENCODING
00097     xdr_destroy(&d_source);
00098 #endif
00099 }
00100 
00101 Crc32::checksum D4StreamUnMarshaller::get_checksum()
00102 {
00103     Crc32::checksum c;
00104     d_in.read(reinterpret_cast<char*>(&c), sizeof(Crc32::checksum));
00105 
00106     return c;
00107 }
00108 
00109 string D4StreamUnMarshaller::get_checksum_str()
00110 {
00111     ostringstream oss;
00112     oss.setf(ios::hex, ios::basefield);
00113     oss << setfill('0') << setw(8) << get_checksum();
00114 
00115     return oss.str();
00116 }
00117 
00118 void
00119 D4StreamUnMarshaller::get_byte( dods_byte &val )
00120 {
00121     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_byte));
00122 }
00123 
00124 void
00125 D4StreamUnMarshaller::get_int8( dods_int8 &val )
00126 {
00127     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int8));
00128 }
00129 
00130 void
00131 D4StreamUnMarshaller::get_int16( dods_int16 &val )
00132 {
00133     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int16));
00134     if (d_twiddle_bytes)
00135         val = bswap_16(val);
00136 }
00137 
00138 void
00139 D4StreamUnMarshaller::get_int32( dods_int32 &val )
00140 {
00141     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int32));
00142     if (d_twiddle_bytes)
00143         val = bswap_32(val);
00144 }
00145 
00146 void
00147 D4StreamUnMarshaller::get_int64( dods_int64 &val )
00148 {
00149     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_int64));
00150     if (d_twiddle_bytes)
00151         val = bswap_64(val);
00152 }
00153 
00154 void
00155 D4StreamUnMarshaller::get_float32( dods_float32 &val )
00156 {
00157 #if !USE_XDR_FOR_IEEE754_ENCODING
00158         assert(std::numeric_limits<float>::is_iec559);
00159 
00160     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float32));
00161     if (d_twiddle_bytes) {
00162         dods_int32 *i = reinterpret_cast<dods_int32*>(&val);
00163         *i = bswap_32(*i);
00164     }
00165 
00166 #else
00167     if (std::numeric_limits<float>::is_iec559) {
00168         d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float32));
00169         if (d_twiddle_bytes) {
00170             dods_int32 *i = reinterpret_cast<dods_int32*>(&val);
00171             *i = bswap_32(*i);
00172         }
00173 
00174     }
00175     else {
00176         xdr_setpos( &d_source, 0);
00177         d_in.read(d_buf, sizeof(dods_float32));
00178 
00179         if (!xdr_float(&d_source, &val))
00180             throw Error("Network I/O Error. Could not read float 64 data.");
00181     }
00182 #endif
00183 }
00184 
00185 void
00186 D4StreamUnMarshaller::get_float64( dods_float64 &val )
00187 {
00188 #if !USE_XDR_FOR_IEEE754_ENCODING
00189         assert(std::numeric_limits<double>::is_iec559);
00190 
00191     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float64));
00192     if (d_twiddle_bytes) {
00193         dods_int64 *i = reinterpret_cast<dods_int64*>(&val);
00194         *i = bswap_64(*i);
00195     }
00196 
00197 #else
00198     if (std::numeric_limits<float>::is_iec559) {
00199         d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_float64));
00200         if (d_twiddle_bytes) {
00201             dods_int64 *i = reinterpret_cast<dods_int64*>(&val);
00202             *i = bswap_64(*i);
00203         }
00204     }
00205     else {
00206         xdr_setpos( &d_source, 0);
00207         d_in.read(d_buf, sizeof(dods_float64));
00208 
00209         if (!xdr_double(&d_source, &val))
00210             throw Error("Network I/O Error. Could not read float 64 data.");
00211     }
00212 #endif
00213 }
00214 
00215 void
00216 D4StreamUnMarshaller::get_uint16( dods_uint16 &val )
00217 {
00218     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint16));
00219     if (d_twiddle_bytes)
00220         val = bswap_16(val);
00221 }
00222 
00223 void
00224 D4StreamUnMarshaller::get_uint32( dods_uint32 &val )
00225 {
00226     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint32));
00227     if (d_twiddle_bytes)
00228         val = bswap_32(val);
00229 }
00230 
00231 void
00232 D4StreamUnMarshaller::get_uint64( dods_uint64 &val )
00233 {
00234     d_in.read(reinterpret_cast<char*>(&val), sizeof(dods_uint64));
00235     if (d_twiddle_bytes)
00236         val = bswap_64(val);
00237 }
00238 
00239 void
00240 D4StreamUnMarshaller::get_str( string &val )
00241 {
00242     int64_t len;
00243     d_in.read(reinterpret_cast<char*>(&len), sizeof(int64_t));
00244 
00245     val.resize(len);
00246     d_in.read(&val[0], len);
00247 }
00248 
00249 void
00250 D4StreamUnMarshaller::get_url( string &val )
00251 {
00252     get_str( val ) ;
00253 }
00254 
00263 int64_t
00264 D4StreamUnMarshaller::get_count()
00265 {
00266         int64_t count;
00267         d_in.read(reinterpret_cast<char*>(&count), sizeof(count));
00268         return count;
00269 }
00270 
00278 void
00279 D4StreamUnMarshaller::get_opaque_dap4( char **val, int64_t &len )
00280 {
00281     //len = get_length_prefix();
00282         d_in.read(reinterpret_cast<char*>(&len), sizeof(len));
00283 
00284     *val = new char[len];
00285     d_in.read(*val, len);
00286 }
00287 
00288 void
00289 D4StreamUnMarshaller::get_opaque_dap4( vector<uint8_t> &val )
00290 {
00291     //len = get_length_prefix();
00292         int64_t len;
00293         d_in.read(reinterpret_cast<char*>(&len), sizeof(len));
00294 
00295     val.resize(len);
00296     d_in.read(reinterpret_cast<char*>(&val[0]), len);
00297 }
00298 
00299 void
00300 D4StreamUnMarshaller::get_vector( char *val, int64_t bytes )
00301 {
00302     d_in.read(val, bytes);
00303 }
00304 
00305 #if USE_XDR_FOR_IEEE754_ENCODING
00306 void D4StreamUnMarshaller::m_deserialize_reals(char *val, int64_t num, int width, Type type)
00307 {
00308     int64_t size = num * width;
00309     // char *buf = (char*)malloc(size); jhrg 7/23/13
00310     vector<char> buf(size);
00311     XDR xdr;
00312     xdrmem_create(&xdr, &buf[0], size, XDR_DECODE);
00313     try {
00314         xdr_setpos(&d_source, 0);
00315         d_in.read(&buf[0], size);
00316 
00317         if(!xdr_array(&xdr, &val, (unsigned int *)&num, size, width, XDRUtils::xdr_coder(type)))
00318             throw InternalErr(__FILE__, __LINE__, "Error deserializing a Float64 array");
00319 
00320         if (xdr_getpos(&xdr) != size)
00321             throw InternalErr(__FILE__, __LINE__, "Error deserializing a Float64 array");
00322     }
00323     catch (...) {
00324         xdr_destroy(&xdr);
00325         throw;
00326     }
00327     xdr_destroy(&xdr);
00328 }
00329 #endif
00330 
00331 void D4StreamUnMarshaller::m_twidle_vector_elements(char *vals, int64_t num, int width)
00332 {
00333     switch (width) {
00334         case 2: {
00335             dods_int16 *local = reinterpret_cast<dods_int16*>(vals);
00336             while (num--) {
00337                 *local = bswap_16(*local);
00338                 local++;
00339             }
00340             break;
00341         }
00342         case 4: {
00343             dods_int32 *local = reinterpret_cast<dods_int32*>(vals);;
00344             while (num--) {
00345                 *local = bswap_32(*local);
00346                 local++;
00347             }
00348             break;
00349         }
00350         case 8: {
00351             dods_int64 *local = reinterpret_cast<dods_int64*>(vals);;
00352             while (num--) {
00353                 *local = bswap_64(*local);
00354                 local++;
00355             }
00356             break;
00357         }
00358         default:
00359             throw InternalErr(__FILE__, __LINE__, "Unrecognized word size.");
00360     }
00361 }
00362 
00363 void
00364 D4StreamUnMarshaller::get_vector(char *val, int64_t num_elem, int elem_size)
00365 {
00366         assert(std::numeric_limits<float>::is_iec559);
00367         assert(std::numeric_limits<double>::is_iec559);
00368         assert(val);
00369         assert(num_elem >= 0);
00370         assert(elem_size > 0);
00371 
00372         int64_t bytes;
00373 
00374         switch (elem_size) {
00375         case 1:
00376                 assert(!"Don't call this method for bytes, use put_vector(val, bytes) instead");
00377                 bytes = num_elem;
00378                 break;
00379         case 2:
00380                 // Don't bother testing the sign bit
00381                 assert(!(num_elem & 0x4000000000000000)); // 0x 40 00 --> 0100 0000
00382                 bytes = num_elem << 1;
00383                 break;
00384         case 4:
00385                 assert(!(num_elem & 0x6000000000000000)); // 0x 60 00 --> 0110 0000
00386                 bytes = num_elem << 2;
00387                 break;
00388         case 8:
00389                 assert(!(num_elem & 0x7000000000000000)); // 0111 0000
00390                 bytes = num_elem << 3;
00391                 break;
00392         default:
00393                 bytes = num_elem * elem_size;
00394                 break;
00395         }
00396 
00397     d_in.read(val, bytes);
00398 
00399     if (d_twiddle_bytes)
00400         m_twidle_vector_elements(val, num_elem, elem_size);
00401 }
00402 
00403 void
00404 D4StreamUnMarshaller::get_vector_float32(char *val, int64_t num_elem)
00405 {
00406 #if !USE_XDR_FOR_IEEE754_ENCODING
00407         assert(std::numeric_limits<float>::is_iec559);
00408         assert(val);
00409         assert(num_elem >= 0);
00410         assert(!(num_elem & 0x6000000000000000)); // 0x 60 00 --> 0110 0000
00411 
00412         int64_t bytes = num_elem << 2;
00413 
00414     d_in.read(val, bytes);
00415 
00416     if (d_twiddle_bytes)
00417         m_twidle_vector_elements(val, num_elem, sizeof(dods_float32));
00418 
00419 #else
00420     if (type == dods_float32_c && !std::numeric_limits<float>::is_iec559) {
00421         // If not using IEEE 754, use XDR to get it that way.
00422         m_deserialize_reals(val, num, 4, type);
00423     }
00424     else if (type == dods_float64_c && !std::numeric_limits<double>::is_iec559) {
00425         m_deserialize_reals(val, num, 8, type);
00426     }
00427     else {
00428         d_in.read(val, num * width);
00429         if (d_twiddle_bytes)
00430             m_twidle_vector_elements(val, num, width);
00431     }
00432 #endif
00433 }
00434 
00435 void
00436 D4StreamUnMarshaller::get_vector_float64(char *val, int64_t num_elem)
00437 {
00438 #if !USE_XDR_FOR_IEEE754_ENCODING
00439         assert(std::numeric_limits<float>::is_iec559);
00440         assert(val);
00441         assert(num_elem >= 0);
00442         assert(!(num_elem & 0x7000000000000000)); // 0x 70 00 --> 0111 0000
00443 
00444         int64_t bytes = num_elem << 3;
00445 
00446     d_in.read(val, bytes);
00447 
00448     if (d_twiddle_bytes)
00449         m_twidle_vector_elements(val, num_elem, sizeof(dods_float64));
00450 
00451 #else
00452     if (type == dods_float32_c && !std::numeric_limits<float>::is_iec559) {
00453         // If not using IEEE 754, use XDR to get it that way.
00454         m_deserialize_reals(val, num, 4, type);
00455     }
00456     else if (type == dods_float64_c && !std::numeric_limits<double>::is_iec559) {
00457         m_deserialize_reals(val, num, 8, type);
00458     }
00459     else {
00460         d_in.read(val, num * width);
00461         if (d_twiddle_bytes)
00462             m_twidle_vector_elements(val, num, width);
00463     }
00464 #endif
00465 }
00466 
00467 void
00468 D4StreamUnMarshaller::dump(ostream &strm) const
00469 {
00470     strm << DapIndent::LMarg << "D4StreamUnMarshaller::dump - ("
00471          << (void *)this << ")" << endl ;
00472 }
00473 
00474 } // namespace libdap
00475