Files
pip/libs/main/math/picrc.h

652 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \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 <http://www.gnu.org/licenses/>.
*/
#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<int L>
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<L> & 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<uint>(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<uint>(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<uint>(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<uint>(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<uint>(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<uint>(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<uint>(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<uint>(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<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l);
return t;
}
//! \~english Convert to int
//! \~russian Преобразование в int
operator int() {
int t(0);
int l = piMin<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l);
return t;
}
//! \~english Convert to long
//! \~russian Преобразование в long
operator long() {
long t(0);
int l = piMin<uint>(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<uint>(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<uint>(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<uint>(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<uint>(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<uint>(L / 8, sizeof(t));
memcpy(&t, data_, l);
return t;
}
//! \~english Addition operator
//! \~russian Оператор сложения
uint_cl<L> operator+(const uint_cl<L> & v) {
uint_cl<L> 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<L> operator&(const uint_cl<L> & v) const {
uint_cl<L> t;
for (int i = 0; i < L / 8; ++i)
t.data_[i] = v.data_[i] & data_[i];
return t;
}
uint_cl<L> operator&(const uchar & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const ushort & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const uint & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const ulong & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const ullong & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const char & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const short & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const int & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const long & v) const { return *this & uint_cl<L>(v); }
uint_cl<L> operator&(const llong & v) const { return *this & uint_cl<L>(v); }
//! \~english Bitwise OR operator
//! \~russian Побитовый оператор ИЛИ
uint_cl<L> operator|(const uint_cl<L> & v) const {
uint_cl<L> t;
for (int i = 0; i < L / 8; ++i)
t.data_[i] = v.data_[i] | data_[i];
return t;
}
uint_cl<L> operator|(const uchar & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const ushort & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const uint & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const ulong & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const ullong & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const char & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const short & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const int & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const long & v) const { return *this | uint_cl<L>(v); }
uint_cl<L> operator|(const llong & v) const { return *this | uint_cl<L>(v); }
//! \~english Bitwise XOR operator
//! \~russian Побитовый оператор исключающее ИЛИ
uint_cl<L> operator^(const uint_cl<L> & v) const {
uint_cl<L> t;
for (int i = 0; i < L / 8; ++i)
t.data_[i] = v.data_[i] ^ data_[i];
return t;
}
uint_cl<L> operator^(const uchar & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const ushort & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const uint & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const ulong & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const ullong & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const char & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const short & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const int & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const long & v) const { return *this ^ uint_cl<L>(v); }
uint_cl<L> operator^(const llong & v) const { return *this ^ uint_cl<L>(v); }
//! \~english Less than operator
//! \~russian Оператор меньше
bool operator<(const uint_cl<L> & 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<L> & 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<L> & 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<L> & 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<L> & 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<L> & 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<L> operator>>(const int & c) const {
uint_cl<L> 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<L> operator>>(const uint & c) const { return (*this << (int)c); }
//! \~english Left shift operator
//! \~russian Оператор побитового сдвига влево
uint_cl<L> operator<<(const int & c) const {
uint_cl<L> 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<L> operator<<(const uint & c) const { return (*this >> (int)c); }
//! \~english In-place bitwise inversion
//! \~russian Побитовая инверсия на месте
uint_cl<L> & inverse() const {
for (int i = 0; i < L / 8; ++i)
data_[i] = ~data_[i];
return *this;
}
//! \~english Returns bitwise inverted copy
//! \~russian Возвращает копию с побитовой инверсией
uint_cl<L> inversed() const {
uint_cl<L> 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<L> reversed() const {
uint_cl<L> 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<uint L, typename N = uint_cl<L>>
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