]> granicus.if.org Git - taglib/commitdiff
Added float conversion functions to ByteVector.
authorTsuda Kageyu <tsuda.kageyu@gmail.com>
Wed, 16 Jul 2014 16:28:02 +0000 (01:28 +0900)
committerTsuda Kageyu <tsuda.kageyu@gmail.com>
Thu, 17 Jul 2014 03:09:14 +0000 (12:09 +0900)
Added CMake checks about IEEE754 compliance.

CMakeLists.txt
ConfigureChecks.cmake
cmake/TestFloatFormat.c [new file with mode: 0644]
cmake/modules/TestFloatFormat.cmake [new file with mode: 0644]
config.h.cmake
taglib/riff/aiff/aiffproperties.cpp
taglib/toolkit/tbytevector.cpp
taglib/toolkit/tbytevector.h
taglib/toolkit/tutils.h
tests/test_bytevector.cpp

index 02eb98934642fc56def637c5c4cdab34ce4849bd..d4469b5dc5cee8215d02f76dd5dee2975be820f6 100644 (file)
@@ -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)
index f2d4cae07c261555d2dfdb8e54b9ca73d141fff7..23830f93d91d333004ac63b04bfe34b9b1260879 100644 (file)
@@ -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 (file)
index 0000000..5f18aaf
--- /dev/null
@@ -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 (file)
index 0000000..0e90cde
--- /dev/null
@@ -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)
+
index f8dcbbde7479d5ab169cd3476169179f93e0f09d..07abffa667cba8fa9ea9f4441871c46792fb6e04 100644 (file)
@@ -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
index 18b973eb06c0c0c41d898e372d5ef395ce971629..1afb4a99b58ed2969738e4a58458eac7e74d40a4 100644 (file)
 
 #include <tstring.h>
 #include <tdebug.h>
-#include <cmath>
-// ldexp is a c99 function, which might not be defined in <cmath>
-// so we pull in math.h too and hope it does the right (wrong) thing
-// wrt. c99 functions in C++
-#include <math.h>
-
 #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<const uchar *>(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;
index 1ecd93d43c93d9e528bf67ea80ad091875bee163..3404ab39b5e2d722168a692f702978b9194fda1d 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <algorithm>
 #include <iostream>
+#include <limits>
+#include <cmath>
 #include <cstdio>
 #include <cstring>
 #include <cstddef>
@@ -238,6 +240,95 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst)
   return ByteVector(reinterpret_cast<const char *>(&value), sizeof(T));
 }
 
+template <typename TFloat, typename TInt, Utils::ByteOrder ENDIAN>
+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 <typename TFloat, typename TInt, Utils::ByteOrder ENDIAN>
+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<char *>(&tmp), sizeof(TInt));
+}
+
+template <Utils::ByteOrder ENDIAN>
+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<ulonglong>(bytes[2]) << 56)
+    | (static_cast<ulonglong>(bytes[3]) << 48)
+    | (static_cast<ulonglong>(bytes[4]) << 40)
+    | (static_cast<ulonglong>(bytes[5]) << 32)
+    | (static_cast<ulonglong>(bytes[6]) << 24)
+    | (static_cast<ulonglong>(bytes[7]) << 16)
+    | (static_cast<ulonglong>(bytes[8]) <<  8)
+    | (static_cast<ulonglong>(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<long double>(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<unsigned long long>(value, mostSignificantByteFirst);
 }
 
+ByteVector ByteVector::fromFloat32LE(float value)
+{
+  return fromFloat<float, uint, Utils::LittleEndian>(value);
+}
+
+ByteVector ByteVector::fromFloat32BE(float value)
+{
+  return fromFloat<float, uint, Utils::BigEndian>(value);
+}
+
+ByteVector ByteVector::fromFloat64LE(double value)
+{
+  return fromFloat<double, ulonglong, Utils::LittleEndian>(value);
+}
+
+ByteVector ByteVector::fromFloat64BE(double value)
+{
+  return fromFloat<double, ulonglong, Utils::BigEndian>(value);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // public members
 ////////////////////////////////////////////////////////////////////////////////
@@ -708,6 +819,36 @@ long long ByteVector::toLongLong(uint offset, bool mostSignificantByteFirst) con
   return toNumber<unsigned long long>(*this, offset, mostSignificantByteFirst);
 }
 
+float ByteVector::toFloat32LE(size_t offset) const
+{
+  return toFloat<float, uint, Utils::LittleEndian>(*this, offset);
+}
+
+float ByteVector::toFloat32BE(size_t offset) const
+{
+  return toFloat<float, uint, Utils::BigEndian>(*this, offset);
+}
+
+double ByteVector::toFloat64LE(size_t offset) const
+{
+  return toFloat<double, ulonglong, Utils::LittleEndian>(*this, offset);
+}
+
+double ByteVector::toFloat64BE(size_t offset) const
+{
+  return toFloat<double, ulonglong, Utils::BigEndian>(*this, offset);
+}
+
+long double ByteVector::toFloat80LE(size_t offset) const
+{
+  return toFloat80<Utils::LittleEndian>(*this, offset);
+}
+
+long double ByteVector::toFloat80BE(size_t offset) const
+{
+  return toFloat80<Utils::BigEndian>(*this, offset);
+}
+
 const char &ByteVector::operator[](int index) const
 {
   return d->data->data[d->offset + index];
index 538565b0a6ea2cb759d2f526c448e8a64dcebaf6..cbdb1d2c923109c14e93fdd8934c112662954205 100644 (file)
@@ -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.
      */
index 4a398d26cdec0cf12c5490f21627a43a46fa9ddd..2ade4d89d5f56e264c2dbc5a03a33347a393875e 100644 (file)
@@ -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
   }
index c6a96198743288987bab690ae3a4cd8b5b9205bc..5614f6954560f0841add7a87360c2d65a0a37a62 100644 (file)
@@ -22,6 +22,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <cstring>
 #include <tbytevector.h>
 #include <tbytevectorlist.h>
 #include <cppunit/extensions/HelperMacros.h>
@@ -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<const char*>(PI32LE), 5);
+    CPPUNIT_ASSERT_EQUAL(31415, static_cast<int>(pi32le.toFloat32LE(1) * 10000));
+
+    ByteVector pi32be(reinterpret_cast<const char*>(PI32BE), 5);
+    CPPUNIT_ASSERT_EQUAL(31415, static_cast<int>(pi32be.toFloat32BE(1) * 10000));
+
+    ByteVector pi64le(reinterpret_cast<const char*>(PI64LE), 9);
+    CPPUNIT_ASSERT_EQUAL(31415, static_cast<int>(pi64le.toFloat64LE(1) * 10000));
+
+    ByteVector pi64be(reinterpret_cast<const char*>(PI64BE), 9);
+    CPPUNIT_ASSERT_EQUAL(31415, static_cast<int>(pi64be.toFloat64BE(1) * 10000));
+
+    ByteVector pi80le(reinterpret_cast<const char*>(PI80LE), 11);
+    CPPUNIT_ASSERT_EQUAL(31415, static_cast<int>(pi80le.toFloat80LE(1) * 10000));
+
+    ByteVector pi80be(reinterpret_cast<const char*>(PI80BE), 11);
+    CPPUNIT_ASSERT_EQUAL(31415, static_cast<int>(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()