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().IgnoreError(); // TODO(b/242598609): Handle Status properly 110 FinalizeAligned(); 111 } 112 113 virtual void UpdateAligned(span<const std::byte> data) = 0; 114 115 virtual void FinalizeAligned() = 0; 116 117 class CallUpdateAligned final : public Output { 118 public: CallUpdateAligned(AlignedChecksum & object)119 constexpr CallUpdateAligned(AlignedChecksum& object) : object_(object) {} 120 121 private: DoWrite(span<const std::byte> data)122 StatusWithSize DoWrite(span<const std::byte> data) override { 123 object_.UpdateAligned(data); 124 return StatusWithSize(data.size()); 125 } 126 127 AlignedChecksum& object_; 128 }; 129 130 CallUpdateAligned output_; 131 AlignedWriterBuffer<kBufferSize> writer_; 132 }; 133 134 } // namespace kvs 135 } // namespace pw 136