// // byte_order_stuff.cpp // libscio // // Created by Bob Polis at 2020-02-14 // Copyright (c) 2020 SwiftCoder. All rights reserved. // #include "libscio.hpp" #include #include #include using namespace sc::io; // data_streamer --------------------------------------------------------------- data_streamer::data_streamer(byte_order bo) : _target_byte_order(bo) {} byte_order data_streamer::cur_byte_order() { uint8_t ch[2] = {0x12, 0x34}; uint16_t* p = reinterpret_cast(ch); return *p == 0x1234 ? byte_order::big_endian : byte_order::little_endian; } std::string data_streamer::get4chars(std::istream& file) const { char buf[4]; file.read(buf, 4); return std::string(buf, 4); } uint32_t data_streamer::getui24(std::istream& file) const { char buf[4] = {0}; file.read(&buf[1], 3); if (cur_byte_order() != _target_byte_order) { char tmp = buf[1]; buf[1] = buf[3]; buf[3] = tmp; } return *reinterpret_cast(buf); } int32_t data_streamer::getsi24(std::istream& file) const { return static_cast(getui24(file)); } double data_streamer::getf80(std::istream& file) const { float_80 val; file.read(reinterpret_cast(val._val), sizeof(val._val)); if (_target_byte_order != byte_order::big_endian) { byte_swap(val._val, sizeof(val._val)); } return val; } void data_streamer::put4chars(const std::string& s, std::ostream& file) const { if (s.size() < 4) { throw std::runtime_error("data_streamer::put4chars: string too short"); } file.write(s.c_str(), 4); } void data_streamer::putui24(uint32_t val, std::ostream& file) const { char* buf = reinterpret_cast(&val); if (cur_byte_order() != _target_byte_order) { char tmp = buf[1]; buf[1] = buf[3]; buf[3] = tmp; } file.write(&buf[1], 3); } void data_streamer::putsi24(int32_t val, std::ostream& file) const { putui24(static_cast(val), file); } void data_streamer::putf80(double val, std::ostream& file) const { float_80 f80 {val}; if (_target_byte_order != byte_order::big_endian) { byte_swap(f80._val, sizeof(f80._val)); } file.write(reinterpret_cast(f80._val), sizeof(f80._val)); } // byte_order_changer ---------------------------------------------------------- byte_order_changer::byte_order_changer(data_streamer* ds, byte_order order) : _data_streamer {ds} { if (ds == nullptr) { std::cerr << "byte_order_changer: no data streamer given\n"; return; } _saved_byte_order = _data_streamer->target_byte_order(); _data_streamer->target_byte_order(order); } byte_order_changer::~byte_order_changer() { if (_data_streamer) { _data_streamer->target_byte_order(_saved_byte_order); } } byte_order_changer::byte_order_changer(byte_order_changer&& other) { _data_streamer = other._data_streamer; _saved_byte_order = other._saved_byte_order; other._data_streamer = nullptr; } byte_order_changer& byte_order_changer::operator=(byte_order_changer&& other) { if (&other != this) { _data_streamer = other._data_streamer; _saved_byte_order = other._saved_byte_order; other._data_streamer = nullptr; } return *this; } // float_80 -------------------------------------------------------------------- /*- * Copyright (c) 2005, 2006 by Marco Trillo * * Permission is hereby granted, free of charge, to any * person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice * shall be included in all copies or substantial portions of * the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Infinite & NAN values for non-IEEE systems */ #ifndef HUGE_VAL #ifdef HUGE #define INFINITE_VALUE HUGE #define NAN_VALUE HUGE #endif #else #define INFINITE_VALUE HUGE_VAL #define NAN_VALUE HUGE_VAL #endif /* * IEEE 754 Extended Precision * * Implementation here is the 80-bit extended precision * format of Motorola 68881, Motorola 68882 and Motorola * 68040 FPUs, as well as Intel 80x87 FPUs. * * See: * http://www.freescale.com/files/32bit/doc/fact_sheet/BR509.pdf */ /* * Exponent range: [-16383,16383] * Precision for mantissa: 64 bits with no hidden bit * Bias: 16383 */ float_80::float_80() : float_80(0) {} float_80::float_80(double in) { int sgn, exp, shift; double fraction, t; unsigned int lexp, hexp; unsigned long low, high; if (in == 0.0) { memset(_val, 0, 10); return; } if (in < 0.0) { in = fabs(in); sgn = 1; } else sgn = 0; fraction = frexp(in, &exp); if (exp == 0 || exp > 16384) { if (exp > 16384) /* infinite value */ low = high = 0; else { low = 0x80000000; high = 0; } exp = 32767; goto done; } fraction = ldexp(fraction, 32); t = floor(fraction); low = (unsigned long) t; fraction -= t; t = floor(ldexp(fraction, 32)); high = (unsigned long) t; /* Convert exponents < -16382 to -16382 (then they will be * stored as -16383) */ if (exp < -16382) { shift = 0 - exp - 16382; high >>= shift; high |= (low << (32 - shift)); low >>= shift; exp = -16382; } exp += 16383 - 1; /* bias */ done: lexp = ((unsigned int) exp) >> 8; hexp = ((unsigned int) exp) & 0xFF; /* big endian */ _val[0] = ((unsigned char) sgn) << 7; _val[0] |= (unsigned char) lexp; _val[1] = (unsigned char) hexp; _val[2] = (unsigned char) (low >> 24); _val[3] = (unsigned char) ((low >> 16) & 0xFF); _val[4] = (unsigned char) ((low >> 8) & 0xFF); _val[5] = (unsigned char) (low & 0xFF); _val[6] = (unsigned char) (high >> 24); _val[7] = (unsigned char) ((high >> 16) & 0xFF); _val[8] = (unsigned char) ((high >> 8) & 0xFF); _val[9] = (unsigned char) (high & 0xFF); } float_80::operator double() const { int sgn, exp; unsigned long low, high; double out; /* Extract the components from the big endian buffer */ sgn = (int) (_val[0] >> 7); exp = ((int) (_val[0] & 0x7F) << 8) | ((int) _val[1]); low = (((unsigned long) _val[2]) << 24) | (((unsigned long) _val[3]) << 16) | (((unsigned long) _val[4]) << 8) | (unsigned long) _val[5]; high = (((unsigned long) _val[6]) << 24) | (((unsigned long) _val[7]) << 16) | (((unsigned long) _val[8]) << 8) | (unsigned long) _val[9]; if (exp == 0 && low == 0 && high == 0) return (sgn ? -0.0 : 0.0); switch (exp) { case 32767: if (low == 0 && high == 0) return (sgn ? -INFINITE_VALUE : INFINITE_VALUE); else return (sgn ? -NAN_VALUE : NAN_VALUE); default: exp -= 16383; /* unbias exponent */ } out = ldexp((double) low, -31 + exp); out += ldexp((double) high, -63 + exp); return (sgn ? -out : out); }