/* * 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 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(1) << ((sizeof(value_type) * 8) - 1) }; private: template 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(value & 0x1); value >>= 1; } return result; } static inline value_type calculate_table_entry(byte_type pos) { value_type value = 0; value = (static_cast(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(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((value & 0xff) ^ byte)); } else { value = (value << 8) ^ read_table(static_cast(((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(c)); return *this; } inline crc & process(signed char c) { processByte(static_cast(c)); return *this; } inline crc & process(unsigned char c) { processByte(mpt::byte_cast(c)); return *this; } inline crc & process(std::byte c) { processByte(mpt::byte_cast(c)); return *this; } template 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 inline crc & process(const Container &data) { operator () (data.begin(), data.end()); return *this; } inline crc & operator () (char c) { processByte(mpt::byte_cast(c)); return *this; } inline crc & operator () (signed char c) { processByte(static_cast(c)); return *this; } inline crc & operator () (unsigned char c) { processByte(mpt::byte_cast(c)); return *this; } inline crc & operator () (std::byte c) { processByte(mpt::byte_cast(c)); return *this; } template 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 inline crc & operator () (const Container &data) { operator () (data.begin(), data.end()); return *this; } template 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 inline crc(const Container &data) : value(initial) { init(); process(data.begin(), data.end()); } }; template typename crc::value_type crc::table[256]; typedef crc crc16; typedef crc crc32; typedef crc crc32_ogg; typedef crc crc32c; typedef crc crc64_jones; } // namespace checksum using mpt::checksum::crc32; using mpt::checksum::crc32_ogg; } // namespace mpt OPENMPT_NAMESPACE_END