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-2022 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 <cstring>
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
36 
37 static const char hexChars[] = "0123456789abcdef";
38 
39 // The char '0' == 0
40 static constexpr int offsetZero = int('0');
41 
42 // The char 'A' (or 'a') == 10
43 static constexpr int offsetAlpha = int('A') - 10;
44 
45 
46 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
47 
48 namespace Foam
49 {
50 
51 // Read hexadecimal value, ignoring leading or intermediate '_'
52 static unsigned char readHexDigit(Istream& is)
53 {
54  // Silently ignore leading or intermediate '_'
55  char c = 0;
56  do
57  {
58  is.read(c);
59  }
60  while (c == '_');
61 
62  if (isdigit(c))
63  {
64  return int(c) - offsetZero;
65  }
66  else if (!isxdigit(c))
67  {
69  << "Illegal hex digit: '" << c << "'"
70  << exit(FatalIOError);
71  }
72 
73  return toupper(c) - offsetAlpha;
74 }
75 
76 } // End namespace Foam
77 
78 
79 namespace
80 {
81 
82 // Copy assign digest from content
83 bool assign
84 (
85  std::array<unsigned char, 20>& digest,
86  const unsigned char* content,
87  std::size_t len
88 )
89 {
90  if (!content || !len)
91  {
92  return false;
93  }
94 
95  if (len == digest.size())
96  {
97  // ie, std::copy
98  for (auto& val : digest)
99  {
100  val = *content;
101  ++content;
102  }
103 
104  return true;
105  }
106 
107  // Skip possible '_' prefix
108  if (*content == '_')
109  {
110  ++content;
111  --len;
112  }
113 
114  // Incorrect length - can never assign
115  if (len != 2*digest.size())
116  {
117  return false;
118  }
119 
120  for (auto& val : digest)
121  {
122  const unsigned char upp = *content++;
123  const unsigned char low = *content++;
124 
125  val = (upp << 4) + low;
126  }
127 
128  return true;
129 }
130 
131 
132 // Byte-wise compare digest contents
133 bool isEqual
134 (
135  const std::array<unsigned char, 20>& digest,
136  const char* hexdigits,
137  std::size_t len
138 )
139 {
140  // Skip possible '_' prefix
141  if (*hexdigits == '_')
142  {
143  ++hexdigits;
144  --len;
145  }
146 
147  // Incorrect length - can never match
148  if (len != 2*digest.size())
149  {
150  return false;
151  }
152 
153  for (const auto& byteVal : digest)
154  {
155  const char upp = hexChars[((byteVal >> 4) & 0xF)];
156  const char low = hexChars[(byteVal & 0xF)];
157 
158  if (upp != *hexdigits++) return false;
159  if (low != *hexdigits++) return false;
160  }
161 
162  return true;
163 }
164 
165 } // End anonymous namespace
166 
167 
168 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
171 {
172  clear();
173 }
174 
175 
176 Foam::SHA1Digest::SHA1Digest(const char* content, std::size_t len)
177 {
178  clear();
179  assign(dig_, reinterpret_cast<const unsigned char*>(content), len);
180 }
181 
182 
183 Foam::SHA1Digest::SHA1Digest(const unsigned char* content, std::size_t len)
184 {
185  clear();
186  assign(dig_, content, len);
187 }
188 
189 
191 {
192  clear();
193  read(is);
194 }
195 
196 
197 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
200 {
201  dig_.fill(0); // Same as memset(dig_.data(), 0, dig_.size());
202 }
203 
204 
205 bool Foam::SHA1Digest::empty() const
206 {
207  for (const auto& byteVal : dig_)
208  {
209  if (byteVal)
210  {
211  return false;
212  }
213  }
214 
215  return true;
216 }
217 
218 
220 {
221  for (auto& byteVal : dig_)
222  {
223  const unsigned char upp = readHexDigit(is);
224  const unsigned char low = readHexDigit(is);
225 
226  byteVal = (upp << 4) + low;
227  }
228 
229  is.check(FUNCTION_NAME);
230  return is;
231 }
232 
233 
234 std::string Foam::SHA1Digest::str(const bool prefixed) const
235 {
236  std::string buf;
237  std::size_t nChar = 0;
238 
239  if (prefixed)
240  {
241  buf.resize(1 + 2*dig_.size());
242  buf[nChar++] = '_';
243  }
244  else
245  {
246  buf.resize(2*dig_.size());
247  }
248 
249  for (const auto& byteVal : dig_)
250  {
251  buf[nChar++] = hexChars[((byteVal >> 4) & 0xF)]; // Upper nibble
252  buf[nChar++] = hexChars[(byteVal & 0xF)]; // Lower nibble
253  }
254 
255  return buf;
256 }
257 
258 
259 Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const
260 {
261  if (prefixed)
262  {
263  os.write('_');
264  }
265 
266  for (const auto& byteVal : dig_)
267  {
268  os.write(hexChars[((byteVal >> 4) & 0xF)]); // Upper nibble
269  os.write(hexChars[(byteVal & 0xF)]); // Lower nibble
270  }
271 
273  return os;
274 }
275 
276 
277 // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
279 bool Foam::SHA1Digest::operator==(const SHA1Digest& rhs) const
280 {
281  return (dig_ == rhs.dig_);
282 }
283 
284 
285 bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const
286 {
287  // Interpret empty string as '0000..'
288  size_t len = hexdigits.length();
289 
290  return len ? isEqual(dig_, hexdigits.data(), len) : empty();
291 }
292 
293 
294 bool Foam::SHA1Digest::operator==(const char* hexdigits) const
295 {
296  // Interpret nullptr or empty string as '0000..'
297  size_t len = (hexdigits ? strlen(hexdigits) : 0);
298 
299  return len ? isEqual(dig_, hexdigits, len) : empty();
300 }
301 
303 bool Foam::SHA1Digest::operator!=(const SHA1Digest& rhs) const
304 {
305  return !this->operator==(rhs);
306 }
307 
309 bool Foam::SHA1Digest::operator!=(const std::string& hexdigits) const
310 {
311  return !this->operator==(hexdigits);
312 }
313 
314 
315 bool Foam::SHA1Digest::operator!=(const char* hexdigits) const
316 {
317  return !this->operator==(hexdigits);
318 }
319 
320 
321 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
324 {
325  return dig.read(is);
326 }
327 
328 
329 Foam::Ostream& Foam::operator<<(Ostream& os, const SHA1Digest& dig)
330 {
331  // Write with prefixed = false
332  return dig.write(os, false);
333 }
334 
335 
336 // ************************************************************************* //
static constexpr int offsetZero
Definition: SHA1Digest.C:33
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:56
bool operator!=(const SHA1Digest &rhs) const
Inequality operator.
Definition: SHA1Digest.C:296
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:30
Istream & operator>>(Istream &, directionInfo &)
SHA1Digest()
Default construct a zero digest.
Definition: SHA1Digest.C:163
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
patchWriters clear()
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:198
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:252
static constexpr int offsetAlpha
Definition: SHA1Digest.C:36
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
void clear()
Reset the digest to zero.
Definition: SHA1Digest.C:192
static unsigned char readHexDigit(Istream &is)
Definition: SHA1Digest.C:45
bool operator==(const SHA1Digest &rhs) const
Equality operator.
Definition: SHA1Digest.C:272
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:227
tmp< faMatrix< Type > > operator==(const faMatrix< Type > &, const faMatrix< Type > &)
Istream & read(Istream &is)
Read (40-byte) text representation.
Definition: SHA1Digest.C:212
static const SHA1Digest null
A null digest (ie, all zero)
Definition: SHA1Digest.H:84
Namespace for OpenFOAM.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...