SHA1Digest.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2019-2025 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "SHA1Digest.H"
30 #include "IOstreams.H"
31 #include <algorithm>
32 #include <cstring>
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
37 
38 static const char hexChars[] = "0123456789abcdef";
39 
40 // The char '0' == 0
41 static constexpr int offsetZero = int('0');
42 
43 // The char 'A' (or 'a') == 10
44 static constexpr int offsetAlpha = int('A') - 10;
45 
46 
47 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
48 
49 namespace Foam
50 {
51 
52 // Read hexadecimal value, ignoring leading or intermediate '_'
53 static unsigned char readHexDigit(Istream& is)
54 {
55  // Silently ignore leading or intermediate '_'
56  char c = 0;
57  do
58  {
59  is.read(c);
60  }
61  while (c == '_');
62 
63  if (isdigit(c))
64  {
65  return int(c) - offsetZero;
66  }
67  else if (!isxdigit(c))
68  {
70  << "Illegal hex digit: '" << c << "'"
71  << exit(FatalIOError);
72  }
73 
74  return toupper(c) - offsetAlpha;
75 }
76 
77 } // End namespace Foam
78 
79 
80 namespace
81 {
82 
83 // Copy assign digest from content
84 bool assign
85 (
86  std::array<unsigned char, 20>& digest,
87  const unsigned char* content,
88  std::size_t len
89 )
90 {
91  if (!content || !len)
92  {
93  return false;
94  }
95 
96  if (len == digest.size())
97  {
98  std::copy_n(content, len, digest.data());
99  return true;
100  }
101 
102  // Skip possible '_' prefix
103  if (*content == '_')
104  {
105  ++content;
106  --len;
107  }
108 
109  // Incorrect length - can never assign
110  if (len != 2*digest.size())
111  {
112  return false;
113  }
114 
115  for (auto& val : digest)
116  {
117  const unsigned char upp = *content++;
118  const unsigned char low = *content++;
119 
120  val = (upp << 4) + low;
121  }
122 
123  return true;
124 }
125 
126 
127 // Byte-wise compare digest contents
128 bool isEqual
129 (
130  const std::array<unsigned char, 20>& digest,
131  const char* hexdigits,
132  std::size_t len
133 )
134 {
135  // Skip possible '_' prefix
136  if (*hexdigits == '_')
137  {
138  ++hexdigits;
139  --len;
140  }
141 
142  // Incorrect length - can never match
143  if (len != 2*digest.size())
144  {
145  return false;
146  }
147 
148  for (const auto& byteVal : digest)
149  {
150  const char upp = hexChars[((byteVal >> 4) & 0xF)];
151  const char low = hexChars[(byteVal & 0xF)];
152 
153  if (upp != *hexdigits++) return false;
154  if (low != *hexdigits++) return false;
155  }
156 
157  return true;
158 }
159 
160 } // End anonymous namespace
161 
162 
163 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
166 {
167  dig_.fill(0);
168 }
169 
170 
171 Foam::SHA1Digest::SHA1Digest(const char* content, std::size_t len)
172 {
173  dig_.fill(0);
174  assign(dig_, reinterpret_cast<const unsigned char*>(content), len);
175 }
176 
177 
178 Foam::SHA1Digest::SHA1Digest(const unsigned char* content, std::size_t len)
179 {
180  dig_.fill(0);
181  assign(dig_, content, len);
182 }
183 
184 
186 {
187  dig_.fill(0);
188  read(is);
189 }
190 
191 
192 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
195 {
196  dig_.fill(0);
197 }
198 
199 
200 bool Foam::SHA1Digest::empty() const
201 {
202  for (const auto& byteVal : dig_)
203  {
204  if (byteVal)
205  {
206  return false;
207  }
208  }
209 
210  return true;
211 }
212 
213 
215 {
216  for (auto& byteVal : dig_)
217  {
218  const unsigned char upp = readHexDigit(is);
219  const unsigned char low = readHexDigit(is);
220 
221  byteVal = (upp << 4) + low;
222  }
223 
224  is.check(FUNCTION_NAME);
225  return is;
226 }
227 
228 
229 std::string Foam::SHA1Digest::str(const bool prefixed) const
230 {
231  std::string buf;
232  int nChar = 0;
233 
234  if (prefixed)
235  {
236  buf.resize(1 + 2*dig_.size());
237  buf[nChar++] = '_';
238  }
239  else
240  {
241  buf.resize(2*dig_.size());
242  }
243 
244  for (const auto& byteVal : dig_)
245  {
246  buf[nChar++] = hexChars[((byteVal >> 4) & 0xF)]; // Upper nibble
247  buf[nChar++] = hexChars[(byteVal & 0xF)]; // Lower nibble
248  }
249 
250  return buf;
251 }
252 
253 
254 Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const
255 {
256  if (prefixed)
257  {
258  os.write('_');
259  }
260 
261  for (const auto& byteVal : dig_)
262  {
263  os.write(hexChars[((byteVal >> 4) & 0xF)]); // Upper nibble
264  os.write(hexChars[(byteVal & 0xF)]); // Lower nibble
265  }
266 
268  return os;
269 }
270 
271 
272 // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
274 bool Foam::SHA1Digest::operator==(const SHA1Digest& rhs) const
275 {
276  return (dig_ == rhs.dig_);
277 }
278 
279 
280 bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const
281 {
282  // Interpret empty string as '0000..'
283  size_t len = hexdigits.length();
284 
285  return len ? isEqual(dig_, hexdigits.data(), len) : empty();
286 }
287 
288 
289 bool Foam::SHA1Digest::operator==(const char* hexdigits) const
290 {
291  // Interpret nullptr or empty string as '0000..'
292  size_t len = (hexdigits ? strlen(hexdigits) : 0);
294  return len ? isEqual(dig_, hexdigits, len) : empty();
295 }
296 
297 
298 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
301 {
302  return dig.read(is);
303 }
304 
305 
306 Foam::Ostream& Foam::operator<<(Ostream& os, const SHA1Digest& dig)
307 {
308  // Write with prefixed = false
309  return dig.write(os, false);
310 }
311 
312 
313 // ************************************************************************* //
static constexpr int offsetZero
Definition: SHA1Digest.C:34
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
virtual Ostream & write(const char c) override
Write character.
Definition: OBJstream.C:69
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:45
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
The SHA1 message digest.
Definition: SHA1Digest.H:57
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
virtual Istream & read(token &)=0
Return next token from stream.
static const char hexChars[]
Definition: SHA1Digest.C:31
Istream & operator>>(Istream &, directionInfo &)
SHA1Digest()
Default construct a zero digest.
Definition: SHA1Digest.C:158
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
void assign(Field< Tout > &result, const Field< T1 > &a, const UnaryOp &op)
Populate a field as the result of a unary operation on an input.
Definition: FieldOps.C:28
bool empty() const
Return true if the digest is empty (ie, all zero).
Definition: SHA1Digest.C:193
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
Ostream & write(Ostream &os, const bool prefixed=false) const
Write (40-byte) text representation, optionally with &#39;_&#39; prefix.
Definition: SHA1Digest.C:247
static constexpr int offsetAlpha
Definition: SHA1Digest.C:37
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:629
void clear()
Reset the digest to zero.
Definition: SHA1Digest.C:187
static unsigned char readHexDigit(Istream &is)
Definition: SHA1Digest.C:46
bool operator==(const SHA1Digest &rhs) const
Equality operator.
Definition: SHA1Digest.C:267
const dimensionedScalar c
Speed of light in a vacuum.
std::string str(const bool prefixed=false) const
Return (40-byte) text representation, optionally with &#39;_&#39; prefix.
Definition: SHA1Digest.C:222
Istream & read(Istream &is)
Read (40-byte) text representation.
Definition: SHA1Digest.C:207
static const SHA1Digest null
A null digest (ie, all zero)
Definition: SHA1Digest.H:85
Namespace for OpenFOAM.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...