From 81807646ca7c3ba294e439695c86bddf7e3ce2be Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Mon, 20 Mar 2023 11:22:50 +0100
Subject: [PATCH] ENH: additional SHA1Digest constructors and methods

- data_bytes(), size_bytes() methods to support broadcasting or
  gather/scatter content. Additional construct from raw bytes
  to support transmitting content.
---
 .../primitives/hashes/SHA1/SHA1Digest.C       | 85 +++++++++++++++++--
 .../primitives/hashes/SHA1/SHA1Digest.H       | 50 ++++++++---
 2 files changed, 118 insertions(+), 17 deletions(-)

diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C
index d91aa119429..934cca0d986 100644
--- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C
+++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.C
@@ -76,9 +76,66 @@ static unsigned char readHexDigit(Istream& is)
 } // End namespace Foam
 
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+namespace
+{
 
-bool Foam::SHA1Digest::isEqual(const char* hexdigits, std::size_t len) const
+// Copy assign digest from content
+bool assign
+(
+    std::array<unsigned char, 20>& digest,
+    const unsigned char* content,
+    std::size_t len
+)
+{
+    if (!content || !len)
+    {
+        return false;
+    }
+
+    if (len == digest.size())
+    {
+        // ie, std::copy
+        for (auto& val : digest)
+        {
+            val = *content;
+            ++content;
+        }
+
+        return true;
+    }
+
+    // Skip possible '_' prefix
+    if (*content == '_')
+    {
+        ++content;
+        --len;
+    }
+
+    // Incorrect length - can never assign
+    if (len != 2*digest.size())
+    {
+        return false;
+    }
+
+    for (auto& val : digest)
+    {
+        const unsigned char upp = *content++;
+        const unsigned char low = *content++;
+
+        val = (upp << 4) + low;
+    }
+
+    return true;
+}
+
+
+// Byte-wise compare digest contents
+bool isEqual
+(
+    const std::array<unsigned char, 20>& digest,
+    const char* hexdigits,
+    std::size_t len
+)
 {
     // Skip possible '_' prefix
     if (*hexdigits == '_')
@@ -88,12 +145,12 @@ bool Foam::SHA1Digest::isEqual(const char* hexdigits, std::size_t len) const
     }
 
     // Incorrect length - can never match
-    if (len != 2*dig_.size())
+    if (len != 2*digest.size())
     {
         return false;
     }
 
-    for (const auto& byteVal : dig_)
+    for (const auto& byteVal : digest)
     {
         const char upp = hexChars[((byteVal >> 4) & 0xF)];
         const char low = hexChars[(byteVal & 0xF)];
@@ -105,6 +162,8 @@ bool Foam::SHA1Digest::isEqual(const char* hexdigits, std::size_t len) const
     return true;
 }
 
+} // End anonymous namespace
+
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -114,6 +173,20 @@ Foam::SHA1Digest::SHA1Digest()
 }
 
 
+Foam::SHA1Digest::SHA1Digest(const char* content, std::size_t len)
+{
+    clear();
+    assign(dig_, reinterpret_cast<const unsigned char*>(content), len);
+}
+
+
+Foam::SHA1Digest::SHA1Digest(const unsigned char* content, std::size_t len)
+{
+    clear();
+    assign(dig_, content, len);
+}
+
+
 Foam::SHA1Digest::SHA1Digest(Istream& is)
 {
     clear();
@@ -214,7 +287,7 @@ bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const
     // Interpret empty string as '0000..'
     size_t len = hexdigits.length();
 
-    return len ? isEqual(hexdigits.data(), len) : empty();
+    return len ? isEqual(dig_, hexdigits.data(), len) : empty();
 }
 
 
@@ -223,7 +296,7 @@ bool Foam::SHA1Digest::operator==(const char* hexdigits) const
     // Interpret nullptr or empty string as '0000..'
     size_t len = (hexdigits ? strlen(hexdigits) : 0);
 
-    return len ? isEqual(hexdigits, len) : empty();
+    return len ? isEqual(dig_, hexdigits, len) : empty();
 }
 
 
diff --git a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H
index c8d0e7fa278..f3b3535f5b8 100644
--- a/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H
+++ b/src/OpenFOAM/primitives/hashes/SHA1/SHA1Digest.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -68,18 +68,12 @@ class SHA1Digest
 
     // Private Member Functions
 
-        //- Pointer to the underlying digest data
-        unsigned char* data()
-        {
-            return dig_.data();
-        }
-
-        //- Byte-wise compare digest contents
-        bool isEqual(const char* hexdigits, std::size_t len) const;
-
         // Permit SHA1 to calculate the digest
         friend class SHA1;
 
+        //- Raw digest data (20 bytes). Non-const access for SHA1
+        unsigned char* data() noexcept { return dig_.data(); }
+
 
 public:
 
@@ -94,9 +88,19 @@ public:
         //- Default construct a zero digest
         SHA1Digest();
 
-        //- Read construct a digest
+        //- Read construct a digest from stringified content
         explicit SHA1Digest(Istream& is);
 
+        //- Construct digest from raw or stringified content.
+        //- The length is 20 for raw digest content and 40 (or 41) for
+        //- stringified versions.
+        SHA1Digest(const char* content, std::size_t len);
+
+        //- Construct digest from raw or stringified content.
+        //- The length is 20 for raw digest content and 40 (or 41) for
+        //- stringified versions.
+        SHA1Digest(const unsigned char* content, std::size_t len);
+
 
     // Member Functions
 
@@ -119,6 +123,30 @@ public:
         Ostream& write(Ostream& os, const bool prefixed=false) const;
 
 
+    // Low-level access
+
+        //- Raw digest data (20 bytes) - const access
+        const unsigned char* cdata() const noexcept { return dig_.data(); }
+
+        //- Raw digest data (20 bytes) - const access
+        const unsigned char* cdata_bytes() const noexcept
+        {
+            return dig_.data();
+        }
+
+        //- Raw digest data (20 bytes) - non-const access. Use with caution!
+        unsigned char* data_bytes() noexcept
+        {
+            return dig_.data();
+        }
+
+        //- The number of bytes in digest (20)
+        static constexpr unsigned size_bytes() noexcept { return 20; }
+
+        //- The dimensioned size of the digest is always 20 bytes
+        static constexpr unsigned max_size() noexcept { return 20; }
+
+
     // Member Operators
 
         //- Equality operator
-- 
GitLab