From e29f1d39e7695ebff50e490f4f3155f229121a32 Mon Sep 17 00:00:00 2001 From: Tsuda Kageyu Date: Thu, 17 Jul 2014 01:28:02 +0900 Subject: [PATCH] Added float conversion functions to ByteVector. Added CMake checks about IEEE754 compliance. --- CMakeLists.txt | 2 + ConfigureChecks.cmake | 25 ++++- cmake/TestFloatFormat.c | 13 +++ cmake/modules/TestFloatFormat.cmake | 60 ++++++++++++ config.h.cmake | 6 +- taglib/riff/aiff/aiffproperties.cpp | 50 +--------- taglib/toolkit/tbytevector.cpp | 141 ++++++++++++++++++++++++++++ taglib/toolkit/tbytevector.h | 78 ++++++++++++++- taglib/toolkit/tutils.h | 40 +++++++- tests/test_bytevector.cpp | 42 ++++++++- 10 files changed, 397 insertions(+), 60 deletions(-) create mode 100644 cmake/TestFloatFormat.c create mode 100644 cmake/modules/TestFloatFormat.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 02eb9893..d4469b5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,8 @@ if(NOT ${CMAKE_VERSION} VERSION_LESS 2.8.12) cmake_policy(SET CMP0022 OLD) endif() +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) + option(ENABLE_STATIC "Make static version of libtag" OFF) if(ENABLE_STATIC) add_definitions(-DTAGLIB_STATIC) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index f2d4cae0..23830f93 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -6,8 +6,9 @@ include(CheckLibraryExists) include(CheckTypeSize) include(CheckCXXSourceCompiles) include(TestBigEndian) +include(TestFloatFormat) -# Check if the size of integral types are suitable. +# Check if the size of numeric types are suitable. check_type_size("short" SIZEOF_SHORT) if(NOT ${SIZEOF_SHORT} EQUAL 2) @@ -29,6 +30,16 @@ if(${SIZEOF_WCHAR_T} LESS 2) MESSAGE(FATAL_ERROR "TagLib requires that wchar_t is sufficient to store a UTF-16 char.") endif() +check_type_size("float" SIZEOF_FLOAT) +if(NOT ${SIZEOF_FLOAT} EQUAL 4) + MESSAGE(FATAL_ERROR "TagLib requires that float is 32-bit wide.") +endif() + +check_type_size("double" SIZEOF_DOUBLE) +if(NOT ${SIZEOF_DOUBLE} EQUAL 8) + MESSAGE(FATAL_ERROR "TagLib requires that double is 64-bit wide.") +endif() + # Determine the CPU byte order. test_big_endian(IS_BIG_ENDIAN) @@ -39,6 +50,18 @@ else() set(SYSTEM_BYTEORDER 2) endif() +# Check if the format of floating point types are suitable. + +test_float_format(FP_IEEE754) +if(${FP_IEEE754} EQUAL 1) + set(FLOAT_BYTEORDER 1) +elseif(${FP_IEEE754} EQUAL 2) + set(FLOAT_BYTEORDER 2) +else() + MESSAGE(FATAL_ERROR "TagLib requires that floating point types are IEEE754 compliant.") +endif() + + # Determine which kind of atomic operations your compiler supports. check_cxx_source_compiles(" diff --git a/cmake/TestFloatFormat.c b/cmake/TestFloatFormat.c new file mode 100644 index 00000000..5f18aafb --- /dev/null +++ b/cmake/TestFloatFormat.c @@ -0,0 +1,13 @@ +int main() +{ + double bin1[] = { + // "*TAGLIB*" encoded as a little-endian floating-point number + (double)3.9865557444897601e-105, (double)0.0 + }; + float bin2[] = { + // "*TL*" encoded as a little-endian floating-point number + (float)1.81480400e-013, (float)0.0 + }; + + return 0; +} diff --git a/cmake/modules/TestFloatFormat.cmake b/cmake/modules/TestFloatFormat.cmake new file mode 100644 index 00000000..0e90cde6 --- /dev/null +++ b/cmake/modules/TestFloatFormat.cmake @@ -0,0 +1,60 @@ +# Returns 1 if IEEE754 little-endian, 2 if IEEE754 big-endian, otherwise 0. + +MACRO(TEST_FLOAT_FORMAT FP_IEEE754) + IF(NOT FP_IEEE754) + TRY_COMPILE(HAVE_${FP_IEEE754} "${CMAKE_BINARY_DIR}" "${CMAKE_SOURCE_DIR}/cmake/TestFloatFormat.c" + COPY_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestFloatFormat.bin") + + SET(FP_IEEE754 0) + + IF(HAVE_${FP_IEEE754}) + + # dont match first/last letter because of string rounding errors :-) + FILE(STRINGS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestFloatFormat.bin" + DOUBLE_IEEE754_LE LIMIT_COUNT 1 REGEX "TAGLIB") + FILE(STRINGS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestFloatFormat.bin" + DOUBLE_IEEE754_BE LIMIT_COUNT 1 REGEX "BILGAT") + FILE(STRINGS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestFloatFormat.bin" + FLOAT_IEEE754_LE LIMIT_COUNT 1 REGEX "TL") + FILE(STRINGS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestFloatFormat.bin" + FLOAT_IEEE754_BE LIMIT_COUNT 1 REGEX "LT") + + IF(DOUBLE_IEEE754_LE AND FLOAT_IEEE754_LE) + SET(FP_IEEE754_LE 1) + ENDIF() + + IF(DOUBLE_IEEE754_BE AND FLOAT_IEEE754_BE) + SET(FP_IEEE754_BE 1) + ENDIF() + + # OS X Universal binaries will contain both strings, set it to the host + IF(FP_IEEE754_LE AND FP_IEEE754_BE) + IF(CMAKE_SYSTEM_PROCESSOR MATCHES powerpc) + SET(FP_IEEE754_LE FALSE) + SET(FP_IEEE754_BE TRUE) + ELSE() + SET(FP_IEEE754_LE TRUE) + SET(FP_IEEE754_BE FALSE) + ENDIF() + ENDIF() + + IF(FP_IEEE754_LE) + SET(FP_IEEE754 1) + ELSEIF(FP_IEEE754_BE) + SET(FP_IEEE754 2) + ENDIF() + ENDIF() + + # just some informational output for the user + IF(FP_IEEE754_LE) + MESSAGE(STATUS "Checking the floating point format - IEEE754 (LittleEndian)") + ELSEIF(FP_IEEE754_BE) + MESSAGE(STATUS "Checking the floating point format - IEEE754 (BigEndian)") + ELSE() + MESSAGE(STATUS "Checking the floating point format - Not IEEE754 or failed to detect.") + ENDIF() + + SET(FP_IEEE754 "${${FP_IEEE754}}" CACHE INTERNAL "Result of TEST_FLOAT_FORMAT" FORCE) + ENDIF() +ENDMACRO(TEST_FLOAT_FORMAT FP_IEEE754) + diff --git a/config.h.cmake b/config.h.cmake index f8dcbbde..07abffa6 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -1,9 +1,13 @@ /* config.h. Generated by cmake from config.h.cmake */ -/* Indicates the byte order of your target system */ +/* Integer byte order of your target system */ /* 1 if little-endian, 2 if big-endian. */ #cmakedefine SYSTEM_BYTEORDER ${SYSTEM_BYTEORDER} +/* IEEE754 byte order of your target system. */ +/* 1 if little-endian, 2 if big-endian. */ +#cmakedefine FLOAT_BYTEORDER ${FLOAT_BYTEORDER} + /* Defined if your compiler supports some byte swap functions */ #cmakedefine HAVE_GCC_BYTESWAP_16 1 #cmakedefine HAVE_GCC_BYTESWAP_32 1 diff --git a/taglib/riff/aiff/aiffproperties.cpp b/taglib/riff/aiff/aiffproperties.cpp index 18b973eb..1afb4a99 100644 --- a/taglib/riff/aiff/aiffproperties.cpp +++ b/taglib/riff/aiff/aiffproperties.cpp @@ -25,56 +25,8 @@ #include #include -#include -// ldexp is a c99 function, which might not be defined in -// so we pull in math.h too and hope it does the right (wrong) thing -// wrt. c99 functions in C++ -#include - #include "aiffproperties.h" -//////////////////////////////////////////////////////////////////////////////// -// nasty 80-bit float helpers -//////////////////////////////////////////////////////////////////////////////// - -#define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) - -static double ConvertFromIeeeExtended(const TagLib::uchar *bytes) -{ - double f; - int expon; - unsigned long hiMant, loMant; - - expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); - - hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | - ((unsigned long)(bytes[3] & 0xFF) << 16) | - ((unsigned long)(bytes[4] & 0xFF) << 8) | - ((unsigned long)(bytes[5] & 0xFF)); - - loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | - ((unsigned long)(bytes[7] & 0xFF) << 16) | - ((unsigned long)(bytes[8] & 0xFF) << 8) | - ((unsigned long)(bytes[9] & 0xFF)); - - if (expon == 0 && hiMant == 0 && loMant == 0) - f = 0; - else { - if(expon == 0x7FFF) /* Infinity or NaN */ - f = HUGE_VAL; - else { - expon -= 16383; - f = ldexp(UnsignedToFloat(hiMant), expon -= 31); - f += ldexp(UnsignedToFloat(loMant), expon -= 32); - } - } - - if(bytes[0] & 0x80) - return -f; - else - return f; -} - using namespace TagLib; class RIFF::AIFF::Properties::PropertiesPrivate @@ -153,7 +105,7 @@ void RIFF::AIFF::Properties::read(const ByteVector &data) d->channels = data.toShort(0U); d->sampleFrames = data.toUInt(2U); d->sampleWidth = data.toShort(6U); - double sampleRate = ConvertFromIeeeExtended(reinterpret_cast(data.data() + 8)); + const long double sampleRate = data.toFloat80BE(8); d->sampleRate = (int)sampleRate; d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0); d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; diff --git a/taglib/toolkit/tbytevector.cpp b/taglib/toolkit/tbytevector.cpp index 1ecd93d4..3404ab39 100644 --- a/taglib/toolkit/tbytevector.cpp +++ b/taglib/toolkit/tbytevector.cpp @@ -29,6 +29,8 @@ #include #include +#include +#include #include #include #include @@ -238,6 +240,95 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst) return ByteVector(reinterpret_cast(&value), sizeof(T)); } +template +TFloat toFloat(const ByteVector &v, size_t offset) +{ + if (offset > v.size() - sizeof(TInt)) { + debug("toFloat() - offset is out of range. Returning 0."); + return 0.0; + } + + union { + TInt i; + TFloat f; + } tmp; + ::memcpy(&tmp, v.data() + offset, sizeof(TInt)); + + if(ENDIAN != Utils::FloatByteOrder) + tmp.i = Utils::byteSwap(tmp.i); + + return tmp.f; +} + +template +ByteVector fromFloat(TFloat value) +{ + union { + TInt i; + TFloat f; + } tmp; + tmp.f = value; + + if(ENDIAN != Utils::FloatByteOrder) + tmp.i = Utils::byteSwap(tmp.i); + + return ByteVector(reinterpret_cast(&tmp), sizeof(TInt)); +} + +template +long double toFloat80(const ByteVector &v, size_t offset) +{ + if(offset > v.size() - 10) { + debug("toFloat80() - offset is out of range. Returning 0."); + return 0.0; + } + + uchar bytes[10]; + ::memcpy(bytes, v.data() + offset, 10); + + if(ENDIAN == Utils::LittleEndian) { + std::swap(bytes[0], bytes[9]); + std::swap(bytes[1], bytes[8]); + std::swap(bytes[2], bytes[7]); + std::swap(bytes[3], bytes[6]); + std::swap(bytes[4], bytes[5]); + } + + // 1-bit sign + const bool negative = ((bytes[0] & 0x80) != 0); + + // 15-bit exponent + const int exponent = ((bytes[0] & 0x7F) << 8) | bytes[1]; + + // 64-bit fraction. Leading 1 is explicit. + const ulonglong fraction + = (static_cast(bytes[2]) << 56) + | (static_cast(bytes[3]) << 48) + | (static_cast(bytes[4]) << 40) + | (static_cast(bytes[5]) << 32) + | (static_cast(bytes[6]) << 24) + | (static_cast(bytes[7]) << 16) + | (static_cast(bytes[8]) << 8) + | (static_cast(bytes[9])); + + long double val; + if(exponent == 0 && fraction == 0) + val = 0; + else { + if(exponent == 0x7FFF) { + debug("toFloat80() - can't handle the infinity or NaN. Returning 0."); + return 0.0; + } + else + val = ::ldexp(static_cast(fraction), exponent - 16383 - 63); + } + + if(negative) + return -val; + else + return val; +} + class DataPrivate : public RefCounter { public: @@ -371,6 +462,26 @@ ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFir return fromNumber(value, mostSignificantByteFirst); } +ByteVector ByteVector::fromFloat32LE(float value) +{ + return fromFloat(value); +} + +ByteVector ByteVector::fromFloat32BE(float value) +{ + return fromFloat(value); +} + +ByteVector ByteVector::fromFloat64LE(double value) +{ + return fromFloat(value); +} + +ByteVector ByteVector::fromFloat64BE(double value) +{ + return fromFloat(value); +} + //////////////////////////////////////////////////////////////////////////////// // public members //////////////////////////////////////////////////////////////////////////////// @@ -708,6 +819,36 @@ long long ByteVector::toLongLong(uint offset, bool mostSignificantByteFirst) con return toNumber(*this, offset, mostSignificantByteFirst); } +float ByteVector::toFloat32LE(size_t offset) const +{ + return toFloat(*this, offset); +} + +float ByteVector::toFloat32BE(size_t offset) const +{ + return toFloat(*this, offset); +} + +double ByteVector::toFloat64LE(size_t offset) const +{ + return toFloat(*this, offset); +} + +double ByteVector::toFloat64BE(size_t offset) const +{ + return toFloat(*this, offset); +} + +long double ByteVector::toFloat80LE(size_t offset) const +{ + return toFloat80(*this, offset); +} + +long double ByteVector::toFloat80BE(size_t offset) const +{ + return toFloat80(*this, offset); +} + const char &ByteVector::operator[](int index) const { return d->data->data[d->offset + index]; diff --git a/taglib/toolkit/tbytevector.h b/taglib/toolkit/tbytevector.h index 538565b0..cbdb1d2c 100644 --- a/taglib/toolkit/tbytevector.h +++ b/taglib/toolkit/tbytevector.h @@ -291,7 +291,7 @@ namespace TagLib { uint toUInt(bool mostSignificantByteFirst = true) const; /*! - * Converts the 4 bytes at \a offset of the vector to an unsigned integer. + * Converts the 4 bytes at \a offset of the vector to an unsigned integer. * * If \a mostSignificantByteFirst is true this will operate left to right * evaluating the integer. For example if \a mostSignificantByteFirst is @@ -303,8 +303,8 @@ namespace TagLib { uint toUInt(uint offset, bool mostSignificantByteFirst = true) const; /*! - * Converts the \a length bytes at \a offset of the vector to an unsigned - * integer. If \a length is larger than 4, the excess is ignored. + * Converts the \a length bytes at \a offset of the vector to an unsigned + * integer. If \a length is larger than 4, the excess is ignored. * * If \a mostSignificantByteFirst is true this will operate left to right * evaluating the integer. For example if \a mostSignificantByteFirst is @@ -383,6 +383,46 @@ namespace TagLib { */ long long toLongLong(uint offset, bool mostSignificantByteFirst = true) const; + /* + * Converts the 4 bytes at \a offset of the vector to a float as an IEEE754 + * 32-bit little-endian floating point number. + */ + float toFloat32LE(size_t offset) const; + + /* + * Converts the 4 bytes at \a offset of the vector to a float as an IEEE754 + * 32-bit big-endian floating point number. + */ + float toFloat32BE(size_t offset) const; + + /* + * Converts the 8 bytes at \a offset of the vector to a double as an IEEE754 + * 64-bit little-endian floating point number. + */ + double toFloat64LE(size_t offset) const; + + /* + * Converts the 8 bytes at \a offset of the vector to a double as an IEEE754 + * 64-bit big-endian floating point number. + */ + double toFloat64BE(size_t offset) const; + + /* + * Converts the 10 bytes at \a offset of the vector to a long double as an + * IEEE754 80-bit little-endian floating point number. + * + * \note This may compromise the precision depends on the size of long double. + */ + long double toFloat80LE(size_t offset) const; + + /* + * Converts the 10 bytes at \a offset of the vector to a long double as an + * IEEE754 80-bit big-endian floating point number. + * + * \note This may compromise the precision depends on the size of long double. + */ + long double toFloat80BE(size_t offset) const; + /*! * Creates a 4 byte ByteVector based on \a value. If * \a mostSignificantByteFirst is true, then this will operate left to right @@ -415,6 +455,38 @@ namespace TagLib { */ static ByteVector fromLongLong(long long value, bool mostSignificantByteFirst = true); + /*! + * Creates a 4 byte ByteVector based on \a value as an IEEE754 32-bit + * little-endian floating point number. + * + * \see fromFloat32BE() + */ + static ByteVector fromFloat32LE(float value); + + /*! + * Creates a 4 byte ByteVector based on \a value as an IEEE754 32-bit + * big-endian floating point number. + * + * \see fromFloat32LE() + */ + static ByteVector fromFloat32BE(float value); + + /*! + * Creates a 8 byte ByteVector based on \a value as an IEEE754 64-bit + * little-endian floating point number. + * + * \see fromFloat64BE() + */ + static ByteVector fromFloat64LE(double value); + + /*! + * Creates a 8 byte ByteVector based on \a value as an IEEE754 64-bit + * big-endian floating point number. + * + * \see fromFloat64LE() + */ + static ByteVector fromFloat64BE(double value); + /*! * Returns a ByteVector based on the CString \a s. */ diff --git a/taglib/toolkit/tutils.h b/taglib/toolkit/tutils.h index 4a398d26..2ade4d89 100644 --- a/taglib/toolkit/tutils.h +++ b/taglib/toolkit/tutils.h @@ -155,11 +155,11 @@ namespace TagLib # if SYSTEM_BYTEORDER == 1 - const ByteOrder SystemByteOrder = LittleEndian; + const ByteOrder SystemByteOrder = LittleEndian; # else - const ByteOrder SystemByteOrder = BigEndian; + const ByteOrder SystemByteOrder = BigEndian; # endif @@ -178,8 +178,40 @@ namespace TagLib else return BigEndian; } - - const ByteOrder SystemByteOrder = systemByteOrder(); + + const ByteOrder SystemByteOrder = systemByteOrder(); + +#endif + +#ifdef FLOAT_BYTEORDER + +# if FLOAT_BYTEORDER == 1 + + const ByteOrder FloatByteOrder = LittleEndian; + +# else + + const ByteOrder FloatByteOrder = BigEndian; + +# endif + +#else + + inline ByteOrder floatByteOrder() + { + double bin[] = { + // "*TAGLIB*" encoded as a little-endian floating-point number + (double) 3.9865557444897601e-105, (double) 0.0 + }; + + char *str = (char*)&bin[0]; + if(strncmp(&str[1], "TAGLIB", 6) == 0) + return LittleEndian; + else + return BigEndian; + } + + const ByteOrder FloatByteOrder = floatByteOrder(); #endif } diff --git a/tests/test_bytevector.cpp b/tests/test_bytevector.cpp index c6a96198..5614f695 100644 --- a/tests/test_bytevector.cpp +++ b/tests/test_bytevector.cpp @@ -22,6 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -38,7 +39,7 @@ class TestByteVector : public CppUnit::TestFixture CPPUNIT_TEST(testRfind1); CPPUNIT_TEST(testRfind2); CPPUNIT_TEST(testToHex); - CPPUNIT_TEST(testToUShort); + CPPUNIT_TEST(testNumericCoversion); CPPUNIT_TEST(testReplace); CPPUNIT_TEST_SUITE_END(); @@ -194,13 +195,50 @@ public: CPPUNIT_ASSERT_EQUAL(ByteVector("f0e1d2c3b4a5968778695a4b3c2d1e0f"), v.toHex()); } - void testToUShort() + void testNumericCoversion() { CPPUNIT_ASSERT_EQUAL((unsigned short)0xFFFF, ByteVector("\xff\xff", 2).toUShort()); CPPUNIT_ASSERT_EQUAL((unsigned short)0x0001, ByteVector("\x00\x01", 2).toUShort()); CPPUNIT_ASSERT_EQUAL((unsigned short)0x0100, ByteVector("\x00\x01", 2).toUShort(false)); CPPUNIT_ASSERT_EQUAL((unsigned short)0xFF01, ByteVector("\xFF\x01", 2).toUShort()); CPPUNIT_ASSERT_EQUAL((unsigned short)0x01FF, ByteVector("\xFF\x01", 2).toUShort(false)); + + const uchar PI32LE[] = { 0x00, 0xdb, 0x0f, 0x49, 0x40 }; + const uchar PI32BE[] = { 0x00, 0x40, 0x49, 0x0f, 0xdb }; + const uchar PI64LE[] = { 0x00, 0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40 }; + const uchar PI64BE[] = { 0x00, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18 }; + const uchar PI80LE[] = { 0x00, 0x00, 0xc0, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, 0x00, 0x40 }; + const uchar PI80BE[] = { 0x00, 0x40, 0x00, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc0, 0x00 }; + + ByteVector pi32le(reinterpret_cast(PI32LE), 5); + CPPUNIT_ASSERT_EQUAL(31415, static_cast(pi32le.toFloat32LE(1) * 10000)); + + ByteVector pi32be(reinterpret_cast(PI32BE), 5); + CPPUNIT_ASSERT_EQUAL(31415, static_cast(pi32be.toFloat32BE(1) * 10000)); + + ByteVector pi64le(reinterpret_cast(PI64LE), 9); + CPPUNIT_ASSERT_EQUAL(31415, static_cast(pi64le.toFloat64LE(1) * 10000)); + + ByteVector pi64be(reinterpret_cast(PI64BE), 9); + CPPUNIT_ASSERT_EQUAL(31415, static_cast(pi64be.toFloat64BE(1) * 10000)); + + ByteVector pi80le(reinterpret_cast(PI80LE), 11); + CPPUNIT_ASSERT_EQUAL(31415, static_cast(pi80le.toFloat80LE(1) * 10000)); + + ByteVector pi80be(reinterpret_cast(PI80BE), 11); + CPPUNIT_ASSERT_EQUAL(31415, static_cast(pi80be.toFloat80BE(1) * 10000)); + + ByteVector pi32le2 = ByteVector::fromFloat32LE(pi32le.toFloat32LE(1)); + CPPUNIT_ASSERT(memcmp(pi32le.data() + 1, pi32le2.data(), 4) == 0); + + ByteVector pi32be2 = ByteVector::fromFloat32BE(pi32be.toFloat32BE(1)); + CPPUNIT_ASSERT(memcmp(pi32be.data() + 1, pi32be2.data(), 4) == 0); + + ByteVector pi64le2 = ByteVector::fromFloat64LE(pi64le.toFloat64LE(1)); + CPPUNIT_ASSERT(memcmp(pi64le.data() + 1, pi64le2.data(), 8) == 0); + + ByteVector pi64be2 = ByteVector::fromFloat64BE(pi64be.toFloat64BE(1)); + CPPUNIT_ASSERT(memcmp(pi64be.data() + 1, pi64be2.data(), 8) == 0); } void testReplace() -- 2.40.0