//! \file picrc.h //! \ingroup Math //! \~\brief //! \~english CRC checksum calculation //! \~russian Вычисление CRC контрольной суммы /*! PIP - Platform Independent Primitives CRC checksum calculator Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PICRC_H #define PICRC_H #include "pistring.h" //! \addtogroup Math //! \{ //! \class uint_cl //! \brief //! \~english Fixed-size unsigned integer class for CRC calculations //! \~russian Класс целого числа фиксированного размера для вычисления CRC //! \details //! \~english Provides arbitrary length unsigned integer support for CRC computation //! \~russian Обеспечивает поддержку целых чисел произвольной длины для вычисления CRC //! \} template class PIP_EXPORT uint_cl { public: //! \~english Default constructor, initializes to zero //! \~russian Конструктор по умолчанию, инициализирует нулём uint_cl() { for (int i = 0; i < L / 8; ++i) data_[i] = 0; } //! \~english Copy constructor //! \~russian Конструктор копирования uint_cl(const uint_cl & v) { for (int i = 0; i < L / 8; ++i) data_[i] = v.data_[i]; } //! \~english Construct from unsigned char //! \~russian Конструктор из unsigned char uint_cl(uchar v) { for (int i = 0; i < L / 8; ++i) data_[i] = (i == 0 ? v : 0); } //! \~english Construct from char //! \~russian Конструктор из char uint_cl(char v) { for (int i = 0; i < L / 8; ++i) data_[i] = (i == 0 ? v : 0); } //! \~english Construct from unsigned short //! \~russian Конструктор из unsigned short uint_cl(ushort v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from short //! \~russian Конструктор из short uint_cl(short v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from unsigned int //! \~russian Конструктор из unsigned int uint_cl(uint v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from int //! \~russian Конструктор из int uint_cl(int v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from unsigned long //! \~russian Конструктор из unsigned long uint_cl(ulong v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from long //! \~russian Конструктор из long uint_cl(long v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from unsigned long long //! \~russian Конструктор из unsigned long long uint_cl(ullong v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Construct from long long //! \~russian Конструктор из long long uint_cl(llong v) { int l = piMin(L / 8, sizeof(v)); memcpy(data_, &v, l); for (int i = l; i < L / 8; ++i) data_[i] = 0; } //! \~english Convert to bool //! \~russian Преобразование в bool operator bool() { for (int i = 0; i < L / 8; ++i) if (data_[i] > 0) return true; return false; } //! \~english Convert to char //! \~russian Преобразование в char operator char() { return (char)data_[0]; } //! \~english Convert to short //! \~russian Преобразование в short operator short() { short t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to int //! \~russian Преобразование в int operator int() { int t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to long //! \~russian Преобразование в long operator long() { long t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to long long //! \~russian Преобразование в long long operator llong() { llong t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to unsigned char //! \~russian Преобразование в unsigned char operator uchar() { return data_[0]; } //! \~english Convert to unsigned short //! \~russian Преобразование в unsigned short operator ushort() { ushort t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to unsigned int //! \~russian Преобразование в unsigned int operator uint() { uint t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to unsigned long //! \~russian Преобразование в unsigned long operator ulong() { ulong t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Convert to unsigned long long //! \~russian Преобразование в unsigned long long operator ullong() { ullong t(0); int l = piMin(L / 8, sizeof(t)); memcpy(&t, data_, l); return t; } //! \~english Addition operator //! \~russian Оператор сложения uint_cl operator+(const uint_cl & v) { uint_cl t; uint cv; bool ov = false; for (int i = 0; i < L / 8; ++i) { cv = v.data_[i] + data_[i]; if (ov) ++cv; ov = cv > 255; t.data_[i] = ov ? cv - 256 : cv; } return t; } //! \~english Bitwise AND operator //! \~russian Побитовый оператор И uint_cl operator&(const uint_cl & v) const { uint_cl t; for (int i = 0; i < L / 8; ++i) t.data_[i] = v.data_[i] & data_[i]; return t; } uint_cl operator&(const uchar & v) const { return *this & uint_cl(v); } uint_cl operator&(const ushort & v) const { return *this & uint_cl(v); } uint_cl operator&(const uint & v) const { return *this & uint_cl(v); } uint_cl operator&(const ulong & v) const { return *this & uint_cl(v); } uint_cl operator&(const ullong & v) const { return *this & uint_cl(v); } uint_cl operator&(const char & v) const { return *this & uint_cl(v); } uint_cl operator&(const short & v) const { return *this & uint_cl(v); } uint_cl operator&(const int & v) const { return *this & uint_cl(v); } uint_cl operator&(const long & v) const { return *this & uint_cl(v); } uint_cl operator&(const llong & v) const { return *this & uint_cl(v); } //! \~english Bitwise OR operator //! \~russian Побитовый оператор ИЛИ uint_cl operator|(const uint_cl & v) const { uint_cl t; for (int i = 0; i < L / 8; ++i) t.data_[i] = v.data_[i] | data_[i]; return t; } uint_cl operator|(const uchar & v) const { return *this | uint_cl(v); } uint_cl operator|(const ushort & v) const { return *this | uint_cl(v); } uint_cl operator|(const uint & v) const { return *this | uint_cl(v); } uint_cl operator|(const ulong & v) const { return *this | uint_cl(v); } uint_cl operator|(const ullong & v) const { return *this | uint_cl(v); } uint_cl operator|(const char & v) const { return *this | uint_cl(v); } uint_cl operator|(const short & v) const { return *this | uint_cl(v); } uint_cl operator|(const int & v) const { return *this | uint_cl(v); } uint_cl operator|(const long & v) const { return *this | uint_cl(v); } uint_cl operator|(const llong & v) const { return *this | uint_cl(v); } //! \~english Bitwise XOR operator //! \~russian Побитовый оператор исключающее ИЛИ uint_cl operator^(const uint_cl & v) const { uint_cl t; for (int i = 0; i < L / 8; ++i) t.data_[i] = v.data_[i] ^ data_[i]; return t; } uint_cl operator^(const uchar & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const ushort & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const uint & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const ulong & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const ullong & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const char & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const short & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const int & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const long & v) const { return *this ^ uint_cl(v); } uint_cl operator^(const llong & v) const { return *this ^ uint_cl(v); } //! \~english Less than operator //! \~russian Оператор меньше bool operator<(const uint_cl & v) const { for (int i = 0; i < L / 8; ++i) { if (v.data_[i] > data_[i]) return true; if (v.data_[i] < data_[i]) return false; } return false; } //! \~english Less than or equal operator //! \~russian Оператор меньше или равно bool operator<=(const uint_cl & v) const { for (int i = 0; i < L / 8; ++i) { if (v.data_[i] > data_[i]) return true; if (v.data_[i] < data_[i]) return false; } return true; } //! \~english Greater than operator //! \~russian Оператор больше bool operator>(const uint_cl & v) const { for (int i = 0; i < L / 8; ++i) { if (v.data_[i] < data_[i]) return true; if (v.data_[i] > data_[i]) return false; } return false; } //! \~english Greater than or equal operator //! \~russian Оператор больше или равно bool operator>=(const uint_cl & v) const { for (int i = 0; i < L / 8; ++i) { if (v.data_[i] < data_[i]) return true; if (v.data_[i] > data_[i]) return false; } return true; } //! \~english Equality operator //! \~russian Оператор равенства bool operator==(const uint_cl & v) const { for (int i = 0; i < L / 8; ++i) if (v.data_[i] != data_[i]) return false; return true; } //! \~english Inequality operator //! \~russian Оператор неравенства bool operator!=(const uint_cl & v) const { for (int i = 0; i < L / 8; ++i) if (v.data_[i] != data_[i]) return true; return false; } bool operator<=(const uint_cl<8> & v1) { return (*(uchar *)data()) <= (*(uchar *)v1.data()); } //! \~english Right shift operator //! \~russian Оператор побитового сдвига вправо uint_cl operator>>(const int & c) const { uint_cl t; int l = L - c; bool bit; if (l <= 0) return t; for (int i = 0; i < l; ++i) { bit = 1 & (data_[(i + c) / 8] >> ((i + c) % 8)); if (bit) t.data_[i / 8] |= (1 << (i % 8)); else t.data_[i / 8] &= ~(1 << (i % 8)); } return t; } uint_cl operator>>(const uint & c) const { return (*this << (int)c); } //! \~english Left shift operator //! \~russian Оператор побитового сдвига влево uint_cl operator<<(const int & c) const { uint_cl t; int l = L - c; bool bit; if (l <= 0) return t; for (int i = c; i < L; ++i) { bit = 1 & (data_[(i - c) / 8] >> ((i - c) % 8)); if (bit) t.data_[i / 8] |= (1 << (i % 8)); else t.data_[i / 8] &= ~(1 << (i % 8)); } return t; } uint_cl operator<<(const uint & c) const { return (*this >> (int)c); } //! \~english In-place bitwise inversion //! \~russian Побитовая инверсия на месте uint_cl & inverse() const { for (int i = 0; i < L / 8; ++i) data_[i] = ~data_[i]; return *this; } //! \~english Returns bitwise inverted copy //! \~russian Возвращает копию с побитовой инверсией uint_cl inversed() const { uint_cl t(*this); for (int i = 0; i < L / 8; ++i) t.data_[i] = ~t.data_[i]; return t; } //! \~english Returns bit-reversed copy //! \~russian Возвращает копию с переставленными битами uint_cl reversed() const { uint_cl t; bool bit; for (int i = 0; i < L; ++i) { bit = 1 & (data_[(L - i - 1) / 8] >> ((L - i - 1) % 8)); if (bit) t.data_[i / 8] |= (1 << (i % 8)); else t.data_[i / 8] &= ~(1 << (i % 8)); } return t; } //! \~english Get const pointer to data //! \~russian Получить константный указатель на данные const uchar * data() const { return data_; } //! \~english Get pointer to data //! \~russian Получить указатель на данные uchar * data() { return data_; } //! \~english Get data length in bytes //! \~russian Получить длину данных в байтах uint length() const { return L / 8; } private: uchar data_[L / 8]; }; //! \~english Reverse byte order //! \~russian Реверс порядка байтов //! \details //! \~english Reverses the bit order within a byte //! \~russian Инвертирует порядок битов в байте inline uchar reverseByte(uchar b) { uchar ret = 0; bool bit; for (int i = 0; i < 8; ++i) { bit = 1 & (b >> (7 - i)); if (bit) ret |= (1 << i); } return ret; } //! \addtogroup Math //! \{ //! \class PICRC //! \brief //! \~english CRC calculator class //! \~russian Класс калькулятора CRC //! \details //! \~english Calculates CRC checksum using configurable polynomial and parameters //! \~russian Вычисляет контрольную сумму CRC с использованием настраиваемого полинома и параметров //! \sa CRC_32, CRC_16, CRC_8 //! \} template> class PIP_EXPORT PICRC { public: //! \~english Default constructor //! \~russian Конструктор по умолчанию //! \note //! \~english Polynomial value defaults to zero //! \~russian Значение полинома по умолчанию ноль PICRC(const N & poly = N()) { poly_ = poly; reverse_poly = true; init_ = inversed(N(0)); out_ = inversed(N(0)); reverse_before_xor = reverse_data = false; initTable(); } //! \~english Constructor with full parameters //! \~russian Конструктор с полными параметрами //! \param poly polynomial value //! \param reverse_poly_ whether to reverse polynomial bits //! \param initial initial CRC value //! \param out_xor XOR value for output PICRC(const N & poly, bool reverse_poly_, const N & initial, const N & out_xor) { poly_ = poly; reverse_poly = reverse_poly_; init_ = initial; out_ = out_xor; reverse_before_xor = reverse_data = false; initTable(); } //! \~english Set initial CRC value //! \~russian Установить начальное значение CRC void setInitial(const N & v) { init_ = v; } //! \~english Set output XOR value //! \~russian Установить значение XOR для вывода void setOutXor(const N & v) { out_ = v; } //! \~english Set polynomial bit reversal //! \~russian Установить реверс битов полинома void setReversePolynome(bool yes) { reverse_poly = yes; initTable(); } //! \~english Set output bit reversal before XOR //! \~russian Установить реверс битов вывода перед XOR void setReverseOutBeforeXOR(bool yes) { reverse_before_xor = yes; } //! \~english Set data byte reversal //! \~russian Установить реверс байтов данных void setReverseDataBytes(bool yes) { reverse_data = yes; } //! \~english Initialize lookup table //! \~russian Инициализировать таблицу поиска void initTable() { N tmp, pol = reverse_poly ? reversed(poly_) : poly_; for (int i = 0; i < 256; ++i) { tmp = uchar(i); for (int j = 0; j < 8; ++j) tmp = ((tmp & 1) ? ((tmp >> 1) ^ pol) : (tmp >> 1)); table[i] = tmp; } } //! \~english Calculate CRC from raw data //! \~russian Вычислить CRC из сырых данных N calculate(const void * data, int size) { N crc = init_; uchar *data_ = (uchar *)data, cb; uchar nTemp; for (int i = 0; i < size; ++i) { cb = data_[i]; if (reverse_data) cb = reverseByte(cb); nTemp = cb ^ uchar(crc); crc = crc >> 8; crc = crc ^ table[nTemp]; } if (reverse_before_xor) crc = reversed(crc); return crc ^ out_; } //! \~english Calculate CRC from PIByteArray //! \~russian Вычислить CRC из PIByteArray N calculate(const PIByteArray & d) { return calculate(d.data(), d.size()); } //! \~english Calculate CRC from null-terminated string //! \~russian Вычислить CRC из нуль-терминированной строки N calculate(const char * str) { PIByteArray s(PIString(str).toByteArray()); return calculate(s.data(), s.size_s()); } private: inline N reversed(const N & v) { return v.reversed(); } inline N inversed(const N & v) { return v.inversed(); } N table[256]; N poly_, init_, out_; bool reverse_poly, reverse_before_xor, reverse_data; }; template<> inline uchar PICRC<8, uchar>::reversed(const uchar & v) { return reverseByte(v); } template<> inline ushort PICRC<16, ushort>::reversed(const ushort & v) { return uint_cl<16>(v).reversed(); } template<> inline uint PICRC<32, uint>::reversed(const uint & v) { return uint_cl<32>(v).reversed(); } template<> inline uchar PICRC<8, uchar>::inversed(const uchar & v) { return ~v; } template<> inline ushort PICRC<16, ushort>::inversed(const ushort & v) { return ~v; } template<> inline uint PICRC<32, uint>::inversed(const uint & v) { return ~v; } //! \~english Standard CRC-32 (Ethernet, ZIP, etc.) //! \~russian Стандартный CRC-32 (Ethernet, ZIP и т.д.) typedef PICRC<32, uint> CRC_32; //! \~english Standard CRC-24 //! \~russian Стандартный CRC-24 typedef PICRC<24> CRC_24; //! \~english Standard CRC-16 //! \~russian Стандартный CRC-16 typedef PICRC<16, ushort> CRC_16; //! \~english Standard CRC-8 //! \~russian Стандартный CRC-8 typedef PICRC<8, uchar> CRC_8; //! \~english Create standard CRC-32 calculator //! \~russian Создать стандартный калькулятор CRC-32 inline CRC_32 standardCRC_32() { return CRC_32(0x04C11DB7, true, 0xFFFFFFFF, 0xFFFFFFFF); } //! \~english Create standard CRC-16 calculator //! \~russian Создать стандартный калькулятор CRC-16 inline CRC_16 standardCRC_16() { return CRC_16(0x8005, true, 0x0, 0x0); } //! \~english Create standard CRC-16 Modbus calculator //! \~russian Создать стандартный калькулятор CRC-16 Modbus inline CRC_16 standardCRC_16_Modbus() { return CRC_16(0x8005, 0xFFFF, 0xFFFF, false); } //! \~english Create standard CRC-8 calculator //! \~russian Создать стандартный калькулятор CRC-8 inline CRC_8 standardCRC_8() { return CRC_8(0xD5, true, 0x0, 0x0); } //! \} #endif // CRC_H