260 lines
4.9 KiB
C++
260 lines
4.9 KiB
C++
/*
|
|
* mptCRC.h
|
|
* --------
|
|
* Purpose: generic CRC implementation
|
|
* Notes : (currently none)
|
|
* Authors: Joern Heusipp
|
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BuildSettings.h"
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
namespace mpt
|
|
{
|
|
|
|
namespace checksum
|
|
{
|
|
|
|
template <typename T, T polynomial, T initial, T resultXOR, bool reverseData>
|
|
class crc
|
|
{
|
|
|
|
public:
|
|
|
|
typedef crc self_type;
|
|
typedef T value_type;
|
|
typedef uint8 byte_type;
|
|
|
|
enum : std::size_t { size_bytes = sizeof(value_type) };
|
|
enum : std::size_t { size_bits = sizeof(value_type) * 8 };
|
|
enum : value_type { top_bit = static_cast<value_type>(1) << ((sizeof(value_type) * 8) - 1) };
|
|
|
|
private:
|
|
|
|
template <typename Tint>
|
|
static inline Tint reverse(Tint value)
|
|
{
|
|
const std::size_t bits = sizeof(Tint) * 8;
|
|
Tint result = 0;
|
|
for(std::size_t i = 0; i < bits; ++i)
|
|
{
|
|
result <<= 1;
|
|
result |= static_cast<Tint>(value & 0x1);
|
|
value >>= 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static inline value_type calculate_table_entry(byte_type pos)
|
|
{
|
|
value_type value = 0;
|
|
value = (static_cast<value_type>(reverseData ? reverse(pos) : pos) << (size_bits - 8));
|
|
for(std::size_t bit = 0; bit < 8; ++bit)
|
|
{
|
|
if(value & top_bit)
|
|
{
|
|
value = (value << 1) ^ polynomial;
|
|
} else
|
|
{
|
|
value = (value << 1);
|
|
}
|
|
}
|
|
value = (reverseData ? reverse(value) : value);
|
|
return value;
|
|
}
|
|
|
|
private:
|
|
|
|
static value_type table[256];
|
|
|
|
static inline void fill_table()
|
|
{
|
|
for(std::size_t i = 0; i < 256; ++i)
|
|
{
|
|
table[i] = calculate_table_entry(static_cast<byte_type>(i));
|
|
}
|
|
}
|
|
|
|
struct table_filler
|
|
{
|
|
inline table_filler()
|
|
{
|
|
self_type::fill_table();
|
|
}
|
|
};
|
|
|
|
static inline void init()
|
|
{
|
|
static table_filler table_filler;
|
|
}
|
|
|
|
private:
|
|
|
|
inline value_type read_table(byte_type pos) const
|
|
{
|
|
return table[pos];
|
|
}
|
|
|
|
private:
|
|
|
|
value_type value;
|
|
|
|
public:
|
|
|
|
crc()
|
|
: value(initial)
|
|
{
|
|
init();
|
|
}
|
|
|
|
inline void processByte(byte_type byte)
|
|
{
|
|
if constexpr(reverseData)
|
|
{
|
|
value = (value >> 8) ^ read_table(static_cast<byte_type>((value & 0xff) ^ byte));
|
|
} else
|
|
{
|
|
value = (value << 8) ^ read_table(static_cast<byte_type>(((value >> (size_bits - 8)) & 0xff) ^ byte));
|
|
}
|
|
}
|
|
|
|
inline value_type result() const
|
|
{
|
|
return (value ^ resultXOR);
|
|
}
|
|
|
|
public:
|
|
|
|
inline operator value_type () const
|
|
{
|
|
return result();
|
|
}
|
|
|
|
inline crc & process(char c)
|
|
{
|
|
processByte(mpt::byte_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
inline crc & process(signed char c)
|
|
{
|
|
processByte(static_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
inline crc & process(unsigned char c)
|
|
{
|
|
processByte(mpt::byte_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
inline crc & process(std::byte c)
|
|
{
|
|
processByte(mpt::byte_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
template <typename InputIt>
|
|
crc & process(InputIt beg, InputIt end)
|
|
{
|
|
for(InputIt it = beg; it != end; ++it)
|
|
{
|
|
static_assert(sizeof(*it) == 1, "1 byte type required");
|
|
process(*it);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <typename Container>
|
|
inline crc & process(const Container &data)
|
|
{
|
|
operator () (data.begin(), data.end());
|
|
return *this;
|
|
}
|
|
|
|
inline crc & operator () (char c)
|
|
{
|
|
processByte(mpt::byte_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
inline crc & operator () (signed char c)
|
|
{
|
|
processByte(static_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
inline crc & operator () (unsigned char c)
|
|
{
|
|
processByte(mpt::byte_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
inline crc & operator () (std::byte c)
|
|
{
|
|
processByte(mpt::byte_cast<byte_type>(c));
|
|
return *this;
|
|
}
|
|
|
|
template <typename InputIt>
|
|
crc & operator () (InputIt beg, InputIt end)
|
|
{
|
|
for(InputIt it = beg; it != end; ++it)
|
|
{
|
|
static_assert(sizeof(*it) == 1, "1 byte type required");
|
|
operator () (*it);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <typename Container>
|
|
inline crc & operator () (const Container &data)
|
|
{
|
|
operator () (data.begin(), data.end());
|
|
return *this;
|
|
}
|
|
|
|
template <typename InputIt>
|
|
crc(InputIt beg, InputIt end)
|
|
: value(initial)
|
|
{
|
|
init();
|
|
for(InputIt it = beg; it != end; ++it)
|
|
{
|
|
static_assert(sizeof(*it) == 1, "1 byte type required");
|
|
process(*it);
|
|
}
|
|
}
|
|
|
|
template <typename Container>
|
|
inline crc(const Container &data)
|
|
: value(initial)
|
|
{
|
|
init();
|
|
process(data.begin(), data.end());
|
|
}
|
|
|
|
};
|
|
|
|
template <typename T, T polynomial, T initial, T resultXOR, bool reverseData>
|
|
typename crc<T, polynomial, initial, resultXOR, reverseData>::value_type crc<T, polynomial, initial, resultXOR, reverseData>::table[256];
|
|
|
|
typedef crc<uint16, 0x8005, 0, 0, true> crc16;
|
|
typedef crc<uint32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true> crc32;
|
|
typedef crc<uint32, 0x04C11DB7, 0, 0, false> crc32_ogg;
|
|
typedef crc<uint32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true> crc32c;
|
|
typedef crc<uint64, 0xAD93D23594C935A9ull, 0xFFFFFFFFFFFFFFFFull, 0, true> crc64_jones;
|
|
|
|
} // namespace checksum
|
|
|
|
using mpt::checksum::crc32;
|
|
using mpt::checksum::crc32_ogg;
|
|
|
|
} // namespace mpt
|
|
|
|
OPENMPT_NAMESPACE_END
|