1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // CRC-32 (CRC32) implementation with initial value 0xFFFFFFFF. This provides C
16 // functions and a C++ class. Use of the C API is discouraged; use the Crc32
17 // class whevener possible.
18 #pragma once
19
20 #include <stddef.h>
21 #include <stdint.h>
22
23 #include "pw_checksum/internal/config.h"
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif // __cplusplus
28
29 // Value of an empty CRC32. May be serve as the starting CRC32 value for
30 // pw_checksum_Crc32Append.
31 #define PW_CHECKSUM_EMPTY_CRC32 ~_PW_CHECKSUM_CRC32_INITIAL_STATE
32
33 // The initial state for internal CRC32 calculations. Do not use this value
34 // directly.
35 #define _PW_CHECKSUM_CRC32_INITIAL_STATE 0xFFFFFFFFu
36
37 // Internal implementation function for CRC32. Do not call it directly.
38 uint32_t _pw_checksum_InternalCrc32EightBit(const void* data,
39 size_t size_bytes,
40 uint32_t state);
41
42 uint32_t _pw_checksum_InternalCrc32FourBit(const void* data,
43 size_t size_bytes,
44 uint32_t state);
45 uint32_t _pw_checksum_InternalCrc32OneBit(const void* data,
46 size_t size_bytes,
47 uint32_t state);
48
49 #if PW_CHECKSUM_CRC32_DEFAULT_IMPL == PW_CHECKSUM_CRC32_8BITS
50 #define _pw_checksum_InternalCrc32 _pw_checksum_InternalCrc32EightBit
51 #elif PW_CHECKSUM_CRC32_DEFAULT_IMPL == PW_CHECKSUM_CRC32_4BITS
52 #define _pw_checksum_InternalCrc32 _pw_checksum_InternalCrc32FourBit
53 #elif PW_CHECKSUM_CRC32_DEFAULT_IMPL == PW_CHECKSUM_CRC32_1BITS
54 #define _pw_checksum_InternalCrc32 _pw_checksum_InternalCrc32OneBit
55 #endif
56
57 // Calculates the CRC32 for the provided data.
pw_checksum_Crc32(const void * data,size_t size_bytes)58 static inline uint32_t pw_checksum_Crc32(const void* data, size_t size_bytes) {
59 return ~_pw_checksum_InternalCrc32(
60 data, size_bytes, _PW_CHECKSUM_CRC32_INITIAL_STATE);
61 }
62
63 // Updates an existing CRC value. The previous_result must have been returned
64 // from a previous CRC32 call.
pw_checksum_Crc32Append(const void * data,size_t size_bytes,uint32_t previous_result)65 static inline uint32_t pw_checksum_Crc32Append(const void* data,
66 size_t size_bytes,
67 uint32_t previous_result) {
68 // CRC32 values are finalized by inverting the bits. The finalization step
69 // must be undone before appending to a prior CRC32 value, then redone so this
70 // function returns a usable value after each call.
71 return ~_pw_checksum_InternalCrc32(data, size_bytes, ~previous_result);
72 }
73
74 #ifdef __cplusplus
75 } // extern "C"
76
77 #include "pw_span/span.h"
78
79 namespace pw::checksum {
80
81 // Calculates the CRC32 for all data passed to Update.
82 //
83 // This class is more efficient than the CRC32 C functions since it doesn't
84 // finalize the value each time it is appended to.
85 template <uint32_t (*kChecksumFunction)(const void*, size_t, uint32_t)>
86 class Crc32Impl {
87 public:
88 // Calculates the CRC32 for the provided data and returns it as a uint32_t.
89 // To update a CRC in multiple pieces, use an instance of the Crc32 class.
Calculate(span<const std::byte> data)90 static uint32_t Calculate(span<const std::byte> data) {
91 return ~kChecksumFunction(
92 data.data(), data.size_bytes(), _PW_CHECKSUM_CRC32_INITIAL_STATE);
93 }
94
Crc32Impl()95 constexpr Crc32Impl() : state_(kInitialValue) {}
96
Update(span<const std::byte> data)97 void Update(span<const std::byte> data) {
98 state_ = kChecksumFunction(data.data(), data.size(), state_);
99 }
100
Update(std::byte data)101 void Update(std::byte data) { Update(span(&data, 1)); }
102
103 // Returns the value of the CRC32 for all data passed to Update.
value()104 uint32_t value() const { return ~state_; }
105
106 // Resets the CRC to the initial value.
clear()107 void clear() { state_ = kInitialValue; }
108
109 private:
110 static constexpr uint32_t kInitialValue = _PW_CHECKSUM_CRC32_INITIAL_STATE;
111
112 uint32_t state_;
113 };
114
115 using Crc32 = Crc32Impl<_pw_checksum_InternalCrc32>;
116 using Crc32EightBit = Crc32Impl<_pw_checksum_InternalCrc32EightBit>;
117 using Crc32FourBit = Crc32Impl<_pw_checksum_InternalCrc32FourBit>;
118 using Crc32OneBit = Crc32Impl<_pw_checksum_InternalCrc32OneBit>;
119
120 } // namespace pw::checksum
121
122 #endif // __cplusplus
123