diff --git a/src/common/bitutils.h b/src/common/bitutils.h index 3461e06e5..dd253412f 100644 --- a/src/common/bitutils.h +++ b/src/common/bitutils.h @@ -2,22 +2,26 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once + #include "types.h" +#include +#include + #ifdef _MSC_VER -#include +#include #endif // Zero-extending helper template -ALWAYS_INLINE constexpr TReturn ZeroExtend(TValue value) +ALWAYS_INLINE static constexpr TReturn ZeroExtend(TValue value) { return static_cast(static_cast::type>( static_cast::type>(value))); } // Sign-extending helper template -ALWAYS_INLINE constexpr TReturn SignExtend(TValue value) +ALWAYS_INLINE static constexpr TReturn SignExtend(TValue value) { return static_cast( static_cast::type>(static_cast::type>(value))); @@ -25,97 +29,97 @@ ALWAYS_INLINE constexpr TReturn SignExtend(TValue value) // Type-specific helpers template -ALWAYS_INLINE constexpr u16 ZeroExtend16(TValue value) +ALWAYS_INLINE static constexpr u16 ZeroExtend16(TValue value) { return ZeroExtend(value); } template -ALWAYS_INLINE constexpr u32 ZeroExtend32(TValue value) +ALWAYS_INLINE static constexpr u32 ZeroExtend32(TValue value) { return ZeroExtend(value); } template -ALWAYS_INLINE constexpr u64 ZeroExtend64(TValue value) +ALWAYS_INLINE static constexpr u64 ZeroExtend64(TValue value) { return ZeroExtend(value); } template -ALWAYS_INLINE constexpr u16 SignExtend16(TValue value) +ALWAYS_INLINE static constexpr u16 SignExtend16(TValue value) { return SignExtend(value); } template -ALWAYS_INLINE constexpr u32 SignExtend32(TValue value) +ALWAYS_INLINE static constexpr u32 SignExtend32(TValue value) { return SignExtend(value); } template -ALWAYS_INLINE constexpr u64 SignExtend64(TValue value) +ALWAYS_INLINE static constexpr u64 SignExtend64(TValue value) { return SignExtend(value); } template -ALWAYS_INLINE constexpr u8 Truncate8(TValue value) +ALWAYS_INLINE static constexpr u8 Truncate8(TValue value) { return static_cast(static_cast::type>(value)); } template -ALWAYS_INLINE constexpr u16 Truncate16(TValue value) +ALWAYS_INLINE static constexpr u16 Truncate16(TValue value) { return static_cast(static_cast::type>(value)); } template -ALWAYS_INLINE constexpr u32 Truncate32(TValue value) +ALWAYS_INLINE static constexpr u32 Truncate32(TValue value) { return static_cast(static_cast::type>(value)); } // BCD helpers -ALWAYS_INLINE constexpr u8 BinaryToBCD(u8 value) +ALWAYS_INLINE static constexpr u8 BinaryToBCD(u8 value) { return ((value / 10) << 4) + (value % 10); } -ALWAYS_INLINE constexpr u8 PackedBCDToBinary(u8 value) +ALWAYS_INLINE static constexpr u8 PackedBCDToBinary(u8 value) { return ((value >> 4) * 10) + (value % 16); } -ALWAYS_INLINE constexpr u8 IsValidBCDDigit(u8 digit) +ALWAYS_INLINE static constexpr u8 IsValidBCDDigit(u8 digit) { return (digit <= 9); } -ALWAYS_INLINE constexpr u8 IsValidPackedBCD(u8 value) +ALWAYS_INLINE static constexpr u8 IsValidPackedBCD(u8 value) { return IsValidBCDDigit(value & 0x0F) && IsValidBCDDigit(value >> 4); } // Boolean to integer -ALWAYS_INLINE constexpr u8 BoolToUInt8(bool value) +ALWAYS_INLINE static constexpr u8 BoolToUInt8(bool value) { return static_cast(value); } -ALWAYS_INLINE constexpr u16 BoolToUInt16(bool value) +ALWAYS_INLINE static constexpr u16 BoolToUInt16(bool value) { return static_cast(value); } -ALWAYS_INLINE constexpr u32 BoolToUInt32(bool value) +ALWAYS_INLINE static constexpr u32 BoolToUInt32(bool value) { return static_cast(value); } -ALWAYS_INLINE constexpr u64 BoolToUInt64(bool value) +ALWAYS_INLINE static constexpr u64 BoolToUInt64(bool value) { return static_cast(value); } // Integer to boolean template -ALWAYS_INLINE constexpr bool ConvertToBool(TValue value) +ALWAYS_INLINE static constexpr bool ConvertToBool(TValue value) { return static_cast(value); } // Unsafe integer to boolean template -ALWAYS_INLINE bool ConvertToBoolUnchecked(TValue value) +ALWAYS_INLINE static bool ConvertToBoolUnchecked(TValue value) { // static_assert(sizeof(uint8) == sizeof(bool)); bool ret; @@ -125,7 +129,7 @@ ALWAYS_INLINE bool ConvertToBoolUnchecked(TValue value) // Generic sign extension template -ALWAYS_INLINE constexpr T SignExtendN(T value) +ALWAYS_INLINE static constexpr T SignExtendN(T value) { // http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend constexpr int shift = 8 * sizeof(T) - NBITS; @@ -134,7 +138,7 @@ ALWAYS_INLINE constexpr T SignExtendN(T value) /// Returns the number of zero bits before the first set bit, going MSB->LSB. template -ALWAYS_INLINE unsigned CountLeadingZeros(T value) +ALWAYS_INLINE static unsigned CountLeadingZeros(T value) { #ifdef _MSC_VER if constexpr (sizeof(value) >= sizeof(u64)) @@ -161,7 +165,7 @@ ALWAYS_INLINE unsigned CountLeadingZeros(T value) /// Returns the number of zero bits before the first set bit, going LSB->MSB. template -ALWAYS_INLINE unsigned CountTrailingZeros(T value) +ALWAYS_INLINE static unsigned CountTrailingZeros(T value) { #ifdef _MSC_VER if constexpr (sizeof(value) >= sizeof(u64)) @@ -183,3 +187,37 @@ ALWAYS_INLINE unsigned CountTrailingZeros(T value) return static_cast(__builtin_ctz(ZeroExtend32(value))); #endif } + +// C++23-like std::byteswap() +template +ALWAYS_INLINE static T ByteSwap(T value) +{ + if constexpr (std::is_signed_v) + { + return static_cast(ByteSwap(std::make_unsigned_t(value))); + } + else if constexpr (std::is_same_v) + { +#ifdef _MSC_VER + return _byteswap_ushort(value); +#else + return __builtin_bswap16(value); +#endif + } + else if constexpr (std::is_same_v) + { +#ifdef _MSC_VER + return _byteswap_ulong(value); +#else + return __builtin_bswap32(value); +#endif + } + else if constexpr (std::is_same_v) + { +#ifdef _MSC_VER + return _byteswap_uint64(value); +#else + return __builtin_bswap64(value); +#endif + } +} diff --git a/src/util/cd_image.cpp b/src/util/cd_image.cpp index 12cc1f50e..aa9c3a7c6 100644 --- a/src/util/cd_image.cpp +++ b/src/util/cd_image.cpp @@ -3,6 +3,7 @@ #include "cd_image.h" #include "common/assert.h" +#include "common/bitutils.h" #include "common/error.h" #include "common/file_system.h" #include "common/log.h" @@ -536,8 +537,8 @@ u16 CDImage::SubChannelQ::ComputeCRC(const Data& data) for (u32 i = 0; i < 10; i++) value = crc16_table[(value >> 8) ^ data[i]] ^ (value << 8); - value = ~value; - return (value >> 8) | (value << 8); + // Invert and swap + return ByteSwap(static_cast(~value)); } bool CDImage::SubChannelQ::IsCRCValid() const