Browse Source

Simplified ByteOrder, and made it less susceptible to UB when reading from non-aligned addresses. Removed ambiguous method ByteOrder::littleEndianInt (c1, c2, c3, c4), which was probably producing the wrong behaviour on big-endian systems

tags/2021-05-28
jules 7 years ago
parent
commit
a632b57e7a
3 changed files with 116 additions and 135 deletions
  1. +2
    -2
      modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp
  2. +112
    -131
      modules/juce_core/memory/juce_ByteOrder.h
  3. +2
    -2
      modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp

+ 2
- 2
modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -157,8 +157,8 @@ const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
//==============================================================================
namespace WavFileHelpers
{
inline int chunkName (const char* const name) noexcept { return (int) ByteOrder::littleEndianInt (name[0], name[1], name[2], name[3]); }
inline size_t roundUpSize (size_t sz) noexcept { return (sz + 3) & ~3u; }
JUCE_CONSTEXPR inline int chunkName (const char* name) noexcept { return (int) ByteOrder::littleEndianInt (name); }
JUCE_CONSTEXPR inline size_t roundUpSize (size_t sz) noexcept { return (sz + 3) & ~3u; }
#if JUCE_MSVC
#pragma pack (push, 1)


+ 112
- 131
modules/juce_core/memory/juce_ByteOrder.h View File

@@ -36,117 +36,121 @@ public:
/** Swaps the upper and lower bytes of a 16-bit integer. */
JUCE_CONSTEXPR static uint16 swap (uint16 value) noexcept;
/** Swaps the upper and lower bytes of a 16-bit integer. */
JUCE_CONSTEXPR static int16 swap (int16 value) noexcept;
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static uint32 swap (uint32 value) noexcept;
/** Reverses the order of the 4 bytes in a 32-bit integer. */
static int32 swap (int32 value) noexcept;
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static uint64 swap (uint64 value) noexcept;
//==============================================================================
/** Swaps the byte order of a 16-bit unsigned int if the CPU is big-endian */
JUCE_CONSTEXPR static uint16 swapIfBigEndian (uint16 value) noexcept;
/** Swaps the byte order of a 32-bit unsigned int if the CPU is big-endian */
static uint32 swapIfBigEndian (uint32 value) noexcept;
/** Swaps the byte order of a 64-bit unsigned int if the CPU is big-endian */
static uint64 swapIfBigEndian (uint64 value) noexcept;
/** Swaps the byte order of a 16-bit signed int if the CPU is big-endian */
JUCE_CONSTEXPR static int16 swapIfBigEndian (int16 value) noexcept;
/** Swaps the byte order of a 32-bit signed int if the CPU is big-endian */
static int32 swapIfBigEndian (int32 value) noexcept;
/** Swaps the byte order of a 64-bit signed int if the CPU is big-endian */
static int64 swapIfBigEndian (int64 value) noexcept;
/** Swaps the byte order of a 32-bit float if the CPU is big-endian */
static float swapIfBigEndian (float value) noexcept;
/** Swaps the byte order of a 64-bit float if the CPU is big-endian */
static double swapIfBigEndian (double value) noexcept;
/** Swaps the byte order of a 16-bit unsigned int if the CPU is little-endian */
JUCE_CONSTEXPR static uint16 swapIfLittleEndian (uint16 value) noexcept;
/** Swaps the byte order of a 32-bit unsigned int if the CPU is little-endian */
static uint32 swapIfLittleEndian (uint32 value) noexcept;
/** Swaps the byte order of a 64-bit unsigned int if the CPU is little-endian */
static uint64 swapIfLittleEndian (uint64 value) noexcept;
/** Swaps the byte order of a 16-bit signed int if the CPU is little-endian */
JUCE_CONSTEXPR static int16 swapIfLittleEndian (int16 value) noexcept;
/** Swaps the byte order of a 32-bit signed int if the CPU is little-endian */
static int32 swapIfLittleEndian (int32 value) noexcept;
/** Reverses the order of the 8 bytes in a 64-bit integer. */
static int64 swap (int64 value) noexcept;
/** Swaps the byte order of a 64-bit signed int if the CPU is little-endian */
static int64 swapIfLittleEndian (int64 value) noexcept;
/** Returns a garbled float which has the reverse byte-order of the original. */
static float swap (float value) noexcept;
/** Swaps the byte order of a 32-bit float if the CPU is little-endian */
static float swapIfLittleEndian (float value) noexcept;
/** Returns a garbled double which has the reverse byte-order of the original. */
static double swap (double value) noexcept;
/** Swaps the byte order of a 64-bit float if the CPU is little-endian */
static double swapIfLittleEndian (double value) noexcept;
//==============================================================================
/** Swaps the byte order of a signed or unsigned integer if the CPU is big-endian */
template <typename Type>
static Type swapIfBigEndian (Type value) noexcept
{
#if JUCE_LITTLE_ENDIAN
return value;
#else
return swap (value);
#endif
}
/** Swaps the byte order of a signed or unsigned integer if the CPU is little-endian */
template <typename Type>
static Type swapIfLittleEndian (Type value) noexcept
{
#if JUCE_LITTLE_ENDIAN
return swap (value);
#else
return value;
#endif
}
//==============================================================================
/** Turns 4 bytes into a little-endian integer. */
static uint32 littleEndianInt (const void* bytes) noexcept;
/** Turns 4 characters into a little-endian integer. */
JUCE_CONSTEXPR static uint32 littleEndianInt (char c1, char c2, char c3, char c4) noexcept;
JUCE_CONSTEXPR static uint32 littleEndianInt (const void* bytes) noexcept;
/** Turns 8 bytes into a little-endian integer. */
static uint64 littleEndianInt64 (const void* bytes) noexcept;
JUCE_CONSTEXPR static uint64 littleEndianInt64 (const void* bytes) noexcept;
/** Turns 2 bytes into a little-endian integer. */
static uint16 littleEndianShort (const void* bytes) noexcept;
JUCE_CONSTEXPR static uint16 littleEndianShort (const void* bytes) noexcept;
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
JUCE_CONSTEXPR static int littleEndian24Bit (const void* bytes) noexcept;
/** Copies a 24-bit number to 3 little-endian bytes. */
static void littleEndian24BitToChars (int32 value, void* destBytes) noexcept;
//==============================================================================
/** Turns 4 bytes into a big-endian integer. */
static uint32 bigEndianInt (const void* bytes) noexcept;
JUCE_CONSTEXPR static uint32 bigEndianInt (const void* bytes) noexcept;
/** Turns 8 bytes into a big-endian integer. */
static uint64 bigEndianInt64 (const void* bytes) noexcept;
JUCE_CONSTEXPR static uint64 bigEndianInt64 (const void* bytes) noexcept;
/** Turns 2 bytes into a big-endian integer. */
static uint16 bigEndianShort (const void* bytes) noexcept;
//==============================================================================
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
static int littleEndian24Bit (const void* bytes) noexcept;
JUCE_CONSTEXPR static uint16 bigEndianShort (const void* bytes) noexcept;
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
static int bigEndian24Bit (const void* bytes) noexcept;
/** Copies a 24-bit number to 3 little-endian bytes. */
static void littleEndian24BitToChars (int value, void* destBytes) noexcept;
JUCE_CONSTEXPR static int bigEndian24Bit (const void* bytes) noexcept;
/** Copies a 24-bit number to 3 big-endian bytes. */
static void bigEndian24BitToChars (int value, void* destBytes) noexcept;
static void bigEndian24BitToChars (int32 value, void* destBytes) noexcept;
//==============================================================================
/** Constructs a 16-bit integer from its constituent bytes, in order of significance. */
JUCE_CONSTEXPR static uint16 makeInt (uint8 leastSig, uint8 mostSig) noexcept;
/** Constructs a 32-bit integer from its constituent bytes, in order of significance. */
JUCE_CONSTEXPR static uint32 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 mostSig) noexcept;
/** Constructs a 64-bit integer from its constituent bytes, in order of significance. */
JUCE_CONSTEXPR static uint64 makeInt (uint8 leastSig, uint8 byte1, uint8 byte2, uint8 byte3,
uint8 byte4, uint8 byte5, uint8 byte6, uint8 mostSig) noexcept;
//==============================================================================
/** Returns true if the current CPU is big-endian. */
JUCE_CONSTEXPR static bool isBigEndian() noexcept;
JUCE_CONSTEXPR static bool isBigEndian() noexcept
{
#if JUCE_LITTLE_ENDIAN
return false;
#else
return true;
#endif
}
private:
ByteOrder() = delete;
JUCE_DECLARE_NON_COPYABLE (ByteOrder)
};
//==============================================================================
JUCE_CONSTEXPR inline uint16 ByteOrder::swap (uint16 v) noexcept { return static_cast<uint16> ((v << 8) | (v >> 8)); }
JUCE_CONSTEXPR inline int16 ByteOrder::swap (int16 v) noexcept { return static_cast<int16> (swap (static_cast<uint16> (v))); }
inline int32 ByteOrder::swap (int32 v) noexcept { return static_cast<int32> (swap (static_cast<uint32> (v))); }
inline int64 ByteOrder::swap (int64 v) noexcept { return static_cast<int64> (swap (static_cast<uint64> (v))); }
inline float ByteOrder::swap (float v) noexcept { union { uint32 asUInt; float asFloat; } n; n.asFloat = v; n.asUInt = swap (n.asUInt); return n.asFloat; }
inline double ByteOrder::swap (double v) noexcept { union { uint64 asUInt; double asFloat; } n; n.asFloat = v; n.asUInt = swap (n.asUInt); return n.asFloat; }
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
#pragma intrinsic (_byteswap_ulong)
#endif
JUCE_CONSTEXPR inline uint16 ByteOrder::swap (uint16 n) noexcept
{
return static_cast<uint16> ((n << 8) | (n >> 8));
}
inline uint32 ByteOrder::swap (uint32 n) noexcept
{
#if JUCE_MAC || JUCE_IOS
@@ -174,66 +178,43 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
#endif
}
#if JUCE_LITTLE_ENDIAN
JUCE_CONSTEXPR inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return v; }
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) noexcept { return v; }
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) noexcept { return v; }
JUCE_CONSTEXPR inline int16 ByteOrder::swapIfBigEndian (const int16 v) noexcept { return v; }
inline int32 ByteOrder::swapIfBigEndian (const int32 v) noexcept { return v; }
inline int64 ByteOrder::swapIfBigEndian (const int64 v) noexcept { return v; }
inline float ByteOrder::swapIfBigEndian (const float v) noexcept { return v; }
inline double ByteOrder::swapIfBigEndian (const double v) noexcept { return v; }
JUCE_CONSTEXPR inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return swap (v); }
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return swap (v); }
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return swap (v); }
JUCE_CONSTEXPR inline int16 ByteOrder::swapIfLittleEndian (const int16 v) noexcept { return static_cast<int16> (swap (static_cast<uint16> (v))); }
inline int32 ByteOrder::swapIfLittleEndian (const int32 v) noexcept { return static_cast<int32> (swap (static_cast<uint32> (v))); }
inline int64 ByteOrder::swapIfLittleEndian (const int64 v) noexcept { return static_cast<int64> (swap (static_cast<uint64> (v))); }
inline float ByteOrder::swapIfLittleEndian (const float v) noexcept { union { uint32 asUInt; float asFloat; } n; n.asFloat = v; n.asUInt = ByteOrder::swap (n.asUInt); return n.asFloat; }
inline double ByteOrder::swapIfLittleEndian (const double v) noexcept { union { uint64 asUInt; double asFloat; } n; n.asFloat = v; n.asUInt = ByteOrder::swap (n.asUInt); return n.asFloat; }
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
JUCE_CONSTEXPR inline uint32 ByteOrder::littleEndianInt (char c1, char c2, char c3, char c4) noexcept { return (((uint32) c4) << 24) + (((uint32) c3) << 16) + (((uint32) c2) << 8) + (uint32) c1; }
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
JUCE_CONSTEXPR inline bool ByteOrder::isBigEndian() noexcept { return false; }
#else
JUCE_CONSTEXPR inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return swap (v); }
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) noexcept { return swap (v); }
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) noexcept { return swap (v); }
JUCE_CONSTEXPR inline int16 ByteOrder::swapIfBigEndian (const int16 v) noexcept { return static_cast<int16> (swap (static_cast<uint16> (v))); }
inline int32 ByteOrder::swapIfBigEndian (const int32 v) noexcept { return static_cast<int16> (swap (static_cast<uint16> (v))); }
inline int64 ByteOrder::swapIfBigEndian (const int64 v) noexcept { return static_cast<int16> (swap (static_cast<uint16> (v))); }
inline float ByteOrder::swapIfBigEndian (const float v) noexcept { union { uint32 asUInt; float asFloat; } n; n.asFloat = v; n.asUInt = ByteOrder::swap (n.asUInt); return n.asFloat; }
inline double ByteOrder::swapIfBigEndian (const double v) noexcept { union { uint64 asUInt; double asFloat; } n; n.asFloat = v; n.asUInt = ByteOrder::swap (n.asUInt); return n.asFloat; }
JUCE_CONSTEXPR inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return v; }
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return v; }
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return v; }
JUCE_CONSTEXPR inline int16 ByteOrder::swapIfLittleEndian (const int16 v) noexcept { return v; }
inline int32 ByteOrder::swapIfLittleEndian (const int32 v) noexcept { return v; }
inline int64 ByteOrder::swapIfLittleEndian (const int64 v) noexcept { return v; }
inline float ByteOrder::swapIfLittleEndian (const float v) noexcept { return v; }
inline double ByteOrder::swapIfLittleEndian (const double v) noexcept { return v; }
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
JUCE_CONSTEXPR inline uint32 ByteOrder::littleEndianInt (char c1, char c2, char c3, char c4) noexcept { return (((uint32) c1) << 24) + (((uint32) c2) << 16) + (((uint32) c3) << 8) + (uint32) c4; }
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
JUCE_CONSTEXPR inline bool ByteOrder::isBigEndian() noexcept { return true; }
#endif
JUCE_CONSTEXPR inline uint16 ByteOrder::makeInt (uint8 b0, uint8 b1) noexcept
{
return static_cast<uint16> (static_cast<uint16> (b0) | (static_cast<uint16> (b1) << 8));
}
JUCE_CONSTEXPR inline uint32 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3) noexcept
{
return static_cast<uint32> (b0) | (static_cast<uint32> (b1) << 8)
| (static_cast<uint32> (b2) << 16) | (static_cast<uint32> (b3) << 24);
}
JUCE_CONSTEXPR inline uint64 ByteOrder::makeInt (uint8 b0, uint8 b1, uint8 b2, uint8 b3, uint8 b4, uint8 b5, uint8 b6, uint8 b7) noexcept
{
return static_cast<uint64> (b0) | (static_cast<uint64> (b1) << 8) | (static_cast<uint64> (b2) << 16) | (static_cast<uint64> (b3) << 24)
| (static_cast<uint64> (b4) << 32) | (static_cast<uint64> (b5) << 40) | (static_cast<uint64> (b6) << 48) | (static_cast<uint64> (b7) << 56);
}
inline int ByteOrder::littleEndian24Bit (const void* const bytes) noexcept { return (int) ((((unsigned int) static_cast<const int8*> (bytes)[2]) << 16) | (((unsigned int) static_cast<const uint8*> (bytes)[1]) << 8) | ((unsigned int) static_cast<const uint8*> (bytes)[0])); }
inline int ByteOrder::bigEndian24Bit (const void* const bytes) noexcept { return (int) ((((unsigned int) static_cast<const int8*> (bytes)[0]) << 16) | (((unsigned int) static_cast<const uint8*> (bytes)[1]) << 8) | ((unsigned int) static_cast<const uint8*> (bytes)[2])); }
inline void ByteOrder::littleEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) value; static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
inline void ByteOrder::bigEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
JUCE_CONSTEXPR inline uint16 ByteOrder::littleEndianShort (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1]); }
JUCE_CONSTEXPR inline uint32 ByteOrder::littleEndianInt (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1],
static_cast<const uint8*> (bytes)[2], static_cast<const uint8*> (bytes)[3]); }
JUCE_CONSTEXPR inline uint64 ByteOrder::littleEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[0], static_cast<const uint8*> (bytes)[1],
static_cast<const uint8*> (bytes)[2], static_cast<const uint8*> (bytes)[3],
static_cast<const uint8*> (bytes)[4], static_cast<const uint8*> (bytes)[5],
static_cast<const uint8*> (bytes)[6], static_cast<const uint8*> (bytes)[7]); }
JUCE_CONSTEXPR inline uint16 ByteOrder::bigEndianShort (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
JUCE_CONSTEXPR inline uint32 ByteOrder::bigEndianInt (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[3], static_cast<const uint8*> (bytes)[2],
static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
JUCE_CONSTEXPR inline uint64 ByteOrder::bigEndianInt64 (const void* bytes) noexcept { return makeInt (static_cast<const uint8*> (bytes)[7], static_cast<const uint8*> (bytes)[6],
static_cast<const uint8*> (bytes)[5], static_cast<const uint8*> (bytes)[4],
static_cast<const uint8*> (bytes)[3], static_cast<const uint8*> (bytes)[2],
static_cast<const uint8*> (bytes)[1], static_cast<const uint8*> (bytes)[0]); }
JUCE_CONSTEXPR inline int32 ByteOrder::littleEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast<const int8*> (bytes)[2]) << 16) | (((uint32) static_cast<const uint8*> (bytes)[1]) << 8) | ((uint32) static_cast<const uint8*> (bytes)[0])); }
JUCE_CONSTEXPR inline int32 ByteOrder::bigEndian24Bit (const void* bytes) noexcept { return (int32) ((((uint32) static_cast<const int8*> (bytes)[0]) << 16) | (((uint32) static_cast<const uint8*> (bytes)[1]) << 8) | ((uint32) static_cast<const uint8*> (bytes)[2])); }
inline void ByteOrder::littleEndian24BitToChars (int32 value, void* destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) value; static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
inline void ByteOrder::bigEndian24BitToChars (int32 value, void* destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
} // namespace juce

+ 2
- 2
modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp View File

@@ -29,8 +29,8 @@ namespace juce
namespace PropertyFileConstants
{
JUCE_CONSTEXPR static const int magicNumber = (int) ByteOrder::littleEndianInt ('P', 'R', 'O', 'P');
JUCE_CONSTEXPR static const int magicNumberCompressed = (int) ByteOrder::littleEndianInt ('C', 'P', 'R', 'P');
JUCE_CONSTEXPR static const int magicNumber = (int) ByteOrder::makeInt ('P', 'R', 'O', 'P');
JUCE_CONSTEXPR static const int magicNumberCompressed = (int) ByteOrder::makeInt ('C', 'P', 'R', 'P');
JUCE_CONSTEXPR static const char* const fileTag = "PROPERTIES";
JUCE_CONSTEXPR static const char* const valueTag = "VALUE";


Loading…
Cancel
Save