1+ #pragma once
2+ #include " ../utility/assert.h"
3+ #include " ../utility/crc.h"
4+ #include " ../utility/meta.h"
5+ #include " ../utility/parameter.h"
6+
7+ #include " ../stream/serialize_traits.h"
8+
9+ namespace bitstream
10+ {
11+ /* *
12+ * @brief Type for checksums
13+ * @tparam Version A unique version number
14+ */
15+ template <uint32_t Version>
16+ struct checksum ;
17+
18+ /* *
19+ * @brief A trait used to serialize a checksum of the @p Version and the rest of the buffer as the first 32 bits.
20+ * This should be called both first and last when reading and writing to a buffer.
21+ * @tparam Version A unique version number
22+ */
23+ template <uint32_t Version>
24+ struct serialize_traits <checksum<Version>>
25+ {
26+ constexpr static uint32_t protocol_version = utility::to_big_endian32_const(Version);
27+ constexpr static uint32_t protocol_size = sizeof (uint32_t );
28+
29+ template <typename Stream>
30+ typename utility::is_writing_t <Stream>
31+ static serialize (Stream& writer) noexcept
32+ {
33+ if (writer.get_num_bits_serialized () == 0 )
34+ return writer.pad_to_size (4 );
35+
36+ uint32_t num_bits = writer.flush ();
37+
38+ BS_ASSERT (num_bits >= 32U );
39+
40+ // Get buffer info
41+ uint8_t * byte_buffer = writer.get_buffer ();
42+ uint32_t num_bytes = writer.get_num_bytes_serialized ();
43+
44+ // Generate checksum of version + data
45+ uint32_t generated_checksum = utility::crc_uint32 (protocol_version, byte_buffer + protocol_size, writer.get_num_bytes_serialized () - protocol_size);
46+
47+ // Put checksum at beginning
48+ uint32_t * buffer = reinterpret_cast <uint32_t *>(byte_buffer);
49+ *buffer = utility::to_big_endian32 (generated_checksum);
50+
51+ return true ;
52+ }
53+
54+ template <typename Stream>
55+ typename utility::is_reading_t <Stream>
56+ static serialize (Stream& reader) noexcept
57+ {
58+ if (reader.get_num_bits_serialized () > 0 )
59+ return true ;
60+
61+ BS_ASSERT (reader.can_serialize_bits (32U ));
62+
63+ // Get buffer info
64+ const uint8_t * byte_buffer = reader.get_buffer ();
65+ uint32_t num_bytes = (reader.get_total_bits () - 1U ) / 8U + 1U ;
66+
67+ // Generate checksum to compare against
68+ uint32_t generated_checksum = utility::crc_uint32 (protocol_version, byte_buffer + protocol_size, num_bytes - protocol_size);
69+
70+ // Read the checksum
71+ uint32_t given_checksum;
72+ BS_ASSERT (reader.serialize_bits (given_checksum, 32U ));
73+
74+ // Compare the checksum
75+ return generated_checksum == given_checksum;
76+ }
77+ };
78+ }
0 commit comments