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 #pragma once 15 16 #include <cstddef> 17 18 #include "pw_kvs/alignment.h" 19 #include "pw_span/span.h" 20 #include "pw_status/status.h" 21 22 namespace pw { 23 namespace kvs { 24 25 class ChecksumAlgorithm { 26 public: 27 // Resets the checksum to its initial state. 28 virtual void Reset() = 0; 29 30 // Updates the checksum with the provided data. 31 virtual void Update(span<const std::byte> data) = 0; 32 33 // Updates the checksum from a pointer and size. Update(const void * data,size_t size_bytes)34 void Update(const void* data, size_t size_bytes) { 35 return Update( 36 span<const std::byte>(static_cast<const std::byte*>(data), size_bytes)); 37 } 38 39 // Returns the final result of the checksum. Update() can no longer be called 40 // after this. The returned span is valid until a call to Reset(). 41 // 42 // Finish MUST be called before calling Verify. Finish()43 span<const std::byte> Finish() { 44 Finalize(); // Implemented by derived classes, if required. 45 return state(); 46 } 47 48 // Returns the size of the checksum state. size_bytes()49 constexpr size_t size_bytes() const { return state_.size(); } 50 51 // Compares a calculated checksum to this checksum's state. The checksum must 52 // be at least as large as size_bytes(). If it is larger, bytes beyond 53 // size_bytes() are ignored. 54 // 55 // Finish MUST be called before calling Verify. 56 Status Verify(span<const std::byte> checksum) const; 57 58 protected: 59 // A derived class provides a span of its state buffer. ChecksumAlgorithm(span<const std::byte> state)60 constexpr ChecksumAlgorithm(span<const std::byte> state) : state_(state) {} 61 62 // Protected destructor prevents deleting ChecksumAlgorithms from the base 63 // class, so that it is safe to have a non-virtual destructor. 64 ~ChecksumAlgorithm() = default; 65 66 // Returns the current checksum state. state()67 constexpr span<const std::byte> state() const { return state_; } 68 69 private: 70 // Checksums that require finalizing operations may override this method. Finalize()71 virtual void Finalize() {} 72 73 span<const std::byte> state_; 74 }; 75 76 // A checksum algorithm for which Verify always passes. This can be used to 77 // disable checksum verification for a particular entry format. 78 class IgnoreChecksum final : public ChecksumAlgorithm { 79 public: IgnoreChecksum()80 constexpr IgnoreChecksum() : ChecksumAlgorithm({}) {} 81 Reset()82 void Reset() override {} Update(span<const std::byte>)83 void Update(span<const std::byte>) override {} 84 }; 85 86 // Calculates a checksum in kAlignmentBytes chunks. Checksum classes can inherit 87 // from this and implement UpdateAligned and FinalizeAligned instead of Update 88 // and Finalize. 89 template <size_t kAlignmentBytes, size_t kBufferSize = kAlignmentBytes> 90 class AlignedChecksum : public ChecksumAlgorithm { 91 public: Update(span<const std::byte> data)92 void Update(span<const std::byte> data) final { 93 writer_.Write(data) 94 .IgnoreError(); // TODO: b/242598609 - Handle Status properly 95 } 96 97 protected: AlignedChecksum(span<const std::byte> state)98 constexpr AlignedChecksum(span<const std::byte> state) 99 : ChecksumAlgorithm(state), 100 output_(*this), 101 writer_(kAlignmentBytes, output_) {} 102 103 ~AlignedChecksum() = default; 104 105 private: 106 static_assert(kBufferSize >= kAlignmentBytes); 107 Finalize()108 void Finalize() final { 109 writer_.Flush() 110 .IgnoreError(); // TODO: b/242598609 - Handle Status properly 111 FinalizeAligned(); 112 } 113 114 virtual void UpdateAligned(span<const std::byte> data) = 0; 115 116 virtual void FinalizeAligned() = 0; 117 118 class CallUpdateAligned final : public Output { 119 public: CallUpdateAligned(AlignedChecksum & object)120 constexpr CallUpdateAligned(AlignedChecksum& object) : object_(object) {} 121 122 private: DoWrite(span<const std::byte> data)123 StatusWithSize DoWrite(span<const std::byte> data) override { 124 object_.UpdateAligned(data); 125 return StatusWithSize(data.size()); 126 } 127 128 AlignedChecksum& object_; 129 }; 130 131 CallUpdateAligned output_; 132 AlignedWriterBuffer<kBufferSize> writer_; 133 }; 134 135 } // namespace kvs 136 } // namespace pw 137