DCCL v5
Loading...
Searching...
No Matches
field_codec_crc.h
1// Copyright 2024:
2// GobySoft, LLC (2013-)
3// Community contributors (see AUTHORS file)
4// File authors:
5// Toby Schneider <toby@gobysoft.org>
6//
7//
8// This file is part of the Dynamic Compact Control Language Library
9// ("DCCL").
10//
11// DCCL is free software: you can redistribute it and/or modify
12// it under the terms of the GNU Lesser General Public License as published by
13// the Free Software Foundation, either version 2.1 of the License, or
14// (at your option) any later version.
15//
16// DCCL is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public License
22// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
23#ifndef DCCLV4FIELDCODECCRCN
24#define DCCLV4FIELDCODECCRCN
25
26#include <cstdint>
27#include <sstream>
28#include <string>
29
30#include "field_codec_default.h"
31
32namespace dccl
33{
34namespace v4
35{
36
43inline uint16_t crc16(const char* data, size_t size)
44{
45 uint16_t crc = 0xFFFF;
46 for (size_t i = 0; i < size; ++i)
47 {
48 crc ^= static_cast<uint16_t>(static_cast<uint8_t>(data[i])) << 8;
49 for (int bit = 0; bit < 8; ++bit)
50 {
51 if (crc & 0x8000)
52 crc = static_cast<uint16_t>((crc << 1) ^ 0x1021);
53 else
54 crc = static_cast<uint16_t>(crc << 1);
55 }
56 }
57 return crc;
58}
59
67inline uint32_t crc32(const char* data, size_t size)
68{
69 uint32_t crc = 0xFFFFFFFF;
70 for (size_t i = 0; i < size; ++i)
71 {
72 crc ^= static_cast<uint8_t>(data[i]);
73 for (int bit = 0; bit < 8; ++bit)
74 {
75 if (crc & 1)
76 crc = (crc >> 1) ^ 0xEDB88320;
77 else
78 crc >>= 1;
79 }
80 }
81 return crc ^ 0xFFFFFFFF;
82}
83
92template <int CRCBits> class CRCCodecBase : public v4::DefaultNumericFieldCodec<uint32>
93{
94 public:
96
97 double min() override { return 0; }
98 double max() override { return (CRCBits == 32) ? static_cast<double>(0xFFFFFFFFu) : static_cast<double>(0xFFFFu); }
99
100 private:
101 Bitset encode() override
102 {
103 return this->v4::DefaultNumericFieldCodec<uint32>::encode(compute_crc_encode());
104 }
105
106 uint32 pre_encode(const uint32& /*field_value*/) override { return compute_crc_encode(); }
107
108 uint32 post_decode(const uint32& wire_value) override
109 {
110 uint32 expected = compute_crc_decode();
111 uint32 received = wire_value;
112 if (expected != received)
113 {
114 std::stringstream ss;
115 ss << "CRC mismatch. Expected: 0x" << std::hex << expected << ", received: 0x"
116 << received
117 << ". Message data may be corrupted.";
118 throw(Exception(ss.str(), this->root_descriptor()));
119 }
120 return wire_value;
121 }
122
123 void validate() override
124 {
125 // min() and max() are hardcoded - skip the parent's has_min/has_max checks and
126 // call validate_numeric_bounds() directly to verify type range constraints.
127 this->validate_numeric_bounds();
128
129 // the CRC is computed over the bits of the message it belongs to, and only the root
130 // message's bits are recovered while decoding
131 FieldCodecBase::require(this->this_descriptor() == this->root_descriptor(),
132 "CRC codecs are only supported in the root message, not in an "
133 "embedded message");
134 }
135
137 uint32 compute_crc_encode() const
138 {
139 const Bitset* bits = this->root_bitset();
140 if (!bits)
141 return 0;
142 Bitset bits_copy = *bits;
143 std::string byte_str = bits_copy.to_byte_string();
144 return compute_crc(byte_str.data(), byte_str.size());
145 }
146
152 uint32 compute_crc_decode() const
153 {
154 const Bitset* bits = this->root_bitset();
155 if (!bits)
156 return 0;
157 // decoded_bits_ already contains only the bits before the CRC field - no trimming needed.
158 Bitset bits_copy = *bits;
159 std::string byte_str = bits_copy.to_byte_string();
160 return compute_crc(byte_str.data(), byte_str.size());
161 }
162
163 static uint32 compute_crc(const char* data, size_t size)
164 {
165 if (CRCBits == 16)
166 return crc16(data, size);
167 else
168 return crc32(data, size);
169 }
170};
171
176class CRC16Codec : public CRCCodecBase<16>
177{
178};
179
184class CRC32Codec : public CRCCodecBase<32>
185{
186};
187
188} // namespace v4
189} // namespace dccl
190
191#endif
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
std::string to_byte_string()
Returns the value of the Bitset to a byte string, where each character represents 8 bits of the Bitse...
Definition bitset.h:300
Exception class for DCCL.
Definition exception.h:47
const Bitset * root_bitset() const
Returns the root Bitset for the current encode or decode operation.
void set_force_use_required(bool force_required=true)
Force the codec to always use the "required" field encoding, regardless of the FieldDescriptor settin...
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
void require(bool b, const std::string &description)
Essentially an assertion to be used in the validate() virtual method.
Provides a basic bounded arbitrary length numeric (double, float, uint32, uint64, int32,...
Bitset encode() override
Encode an empty field.
unsigned size() override
The size of the encoded message in bits. Use TypedFieldCodec if the size depends on the data.
DCCL CRC-16 codec (CRC-16/IBM-3740 / CCITT-FALSE).
DCCL CRC-32 codec (CRC-32/ISO-HDLC).
DCCL CRC field codec base class. Computes a CRC over all bits encoded before this field (during encod...
uint32_t crc32(const char *data, size_t size)
Computes a CRC-32/ISO-HDLC checksum (standard Ethernet/zlib CRC-32).
uint16_t crc16(const char *data, size_t size)
Computes a CRC-16/IBM-3740 (CRC-16/CCITT-FALSE) checksum.
Dynamic Compact Control Language namespace.
Definition any.h:28
google::protobuf::uint32 uint32
an unsigned 32 bit integer
Definition common.h:56