ENH: allow '_' prefix when reading/writing SHA1Digest

- the resulting SHA1 can be written and parsed directly
  without any ambiguities when it starts with a digit
  eg, SHA1: _024ea2fa570968069f52f55aa47ee82ac417f5f6

- provide same optional prefix functionality in conversion to string
  and in comparison with strings

- add SHA1Digest::null
This commit is contained in:
Mark Olesen
2011-02-25 14:53:12 +01:00
parent 74bc658fe9
commit 0484d1b25b
3 changed files with 147 additions and 79 deletions

View File

@ -151,7 +151,7 @@ void Foam::SHA1::processBytes(const void *data, size_t len)
// while (len > 64) // while (len > 64)
while (len >= 64) while (len >= 64)
{ {
processBlock(memcpy (buffer_, data, 64), 64); processBlock(memcpy(buffer_, data, 64), 64);
data = reinterpret_cast<const unsigned char*>(data) + 64; data = reinterpret_cast<const unsigned char*>(data) + 64;
len -= 64; len -= 64;
} }
@ -177,7 +177,7 @@ void Foam::SHA1::processBytes(const void *data, size_t len)
{ {
processBlock(buffer_, 64); processBlock(buffer_, 64);
remaining -= 64; remaining -= 64;
memcpy (buffer_, &buffer_[16], remaining); memcpy(buffer_, &buffer_[16], remaining);
} }
bufLen_ = remaining; bufLen_ = remaining;
} }
@ -241,10 +241,10 @@ Foam::SHA1::processBlock(const void *data, size_t len)
while (words < endp) while (words < endp)
{ {
uint32_t tm; uint32_t tm;
for (int t = 0; t < 16; t++) for (int t = 0; t < 16; ++t)
{ {
x[t] = swapBytes (*words); x[t] = swapBytes(*words);
words++; ++words;
} }
R( a, b, c, d, e, F1, K1, x[ 0] ); R( a, b, c, d, e, F1, K1, x[ 0] );
@ -343,11 +343,11 @@ void Foam::SHA1::calcDigest(SHA1Digest& dig) const
{ {
unsigned char *r = dig.v_; unsigned char *r = dig.v_;
set_uint32 (r + 0 * sizeof(uint32_t), swapBytes(hashsumA_)); set_uint32(r + 0 * sizeof(uint32_t), swapBytes(hashsumA_));
set_uint32 (r + 1 * sizeof(uint32_t), swapBytes(hashsumB_)); set_uint32(r + 1 * sizeof(uint32_t), swapBytes(hashsumB_));
set_uint32 (r + 2 * sizeof(uint32_t), swapBytes(hashsumC_)); set_uint32(r + 2 * sizeof(uint32_t), swapBytes(hashsumC_));
set_uint32 (r + 3 * sizeof(uint32_t), swapBytes(hashsumD_)); set_uint32(r + 3 * sizeof(uint32_t), swapBytes(hashsumD_));
set_uint32 (r + 4 * sizeof(uint32_t), swapBytes(hashsumE_)); set_uint32(r + 4 * sizeof(uint32_t), swapBytes(hashsumE_));
} }
else else
{ {

View File

@ -30,6 +30,8 @@ License
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::SHA1Digest Foam::SHA1Digest::null;
//! \cond fileScope //! \cond fileScope
static const char hexChars[] = "0123456789abcdef"; static const char hexChars[] = "0123456789abcdef";
//! \endcond //! \endcond
@ -40,12 +42,18 @@ static const char hexChars[] = "0123456789abcdef";
unsigned char Foam::SHA1Digest::readHexDigit(Istream& is) unsigned char Foam::SHA1Digest::readHexDigit(Istream& is)
{ {
// Takes into account that 'a' (or 'A') is 10 // Takes into account that 'a' (or 'A') is 10
static const label alphaOffset = toupper('A') - 10; static const int alphaOffset = toupper('A') - 10;
// Takes into account that '0' is 0 // Takes into account that '0' is 0
static const label zeroOffset = int('0'); static const int zeroOffset = int('0');
// silently ignore leading or intermediate '_'
char c = 0; char c = 0;
is.read(c); do
{
is.read(c);
}
while (c == '_');
if (!isxdigit(c)) if (!isxdigit(c))
{ {
@ -101,12 +109,21 @@ bool Foam::SHA1Digest::empty() const
} }
std::string Foam::SHA1Digest::str() const std::string Foam::SHA1Digest::str(const bool prefixed) const
{ {
std::string buf; std::string buf;
buf.resize(length*2);
unsigned nChar = 0; unsigned nChar = 0;
if (prefixed)
{
buf.resize(1 + length*2);
buf[nChar++] = '_';
}
else
{
buf.resize(length*2);
}
for (unsigned i = 0; i < length; ++i) for (unsigned i = 0; i < length; ++i)
{ {
buf[nChar++] = hexChars[((v_[i] >> 4) & 0xF)]; buf[nChar++] = hexChars[((v_[i] >> 4) & 0xF)];
@ -117,6 +134,24 @@ std::string Foam::SHA1Digest::str() const
} }
Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const
{
if (prefixed)
{
os.write('_');
}
for (unsigned i = 0; i < length; ++i)
{
os.write(hexChars[((v_[i] >> 4) & 0xF)]);
os.write(hexChars[(v_[i] & 0xF)]);
}
os.check("SHA1Digest::write(Ostream&, const bool)");
return os;
}
// * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
bool Foam::SHA1Digest::operator==(const SHA1Digest& rhs) const bool Foam::SHA1Digest::operator==(const SHA1Digest& rhs) const
@ -141,21 +176,26 @@ bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const
return empty(); return empty();
} }
// skip possible '_' prefix
unsigned charI = 0;
if (hexdigits[0] == '_')
{
++charI;
}
// incorrect length - can never match // incorrect length - can never match
if (hexdigits.size() != length*2) if (hexdigits.size() != charI + length*2)
{ {
return false; return false;
} }
for (unsigned i = 0, charI = 0; i < length; ++i, charI += 2) for (unsigned i = 0; i < length; ++i)
{ {
const char c1 = hexChars[((v_[i] >> 4) & 0xF)]; const char c1 = hexChars[((v_[i] >> 4) & 0xF)];
const char c2 = hexChars[(v_[i] & 0xF)]; const char c2 = hexChars[(v_[i] & 0xF)];
if (c1 != hexdigits[charI] || c2 != hexdigits[charI+1]) if (c1 != hexdigits[charI++]) return false;
{ if (c2 != hexdigits[charI++]) return false;
return false;
}
} }
return true; return true;
@ -170,21 +210,26 @@ bool Foam::SHA1Digest::operator==(const char* hexdigits) const
return empty(); return empty();
} }
// skip possible '_' prefix
unsigned charI = 0;
if (hexdigits[0] == '_')
{
++charI;
}
// incorrect length - can never match // incorrect length - can never match
if (strlen(hexdigits) != length*2) if (strlen(hexdigits) != charI + length*2)
{ {
return false; return false;
} }
for (unsigned i = 0, charI = 0; i < length; ++i, charI += 2) for (unsigned i = 0; i < length; ++i)
{ {
const char c1 = hexChars[((v_[i] >> 4) & 0xF)]; const char c1 = hexChars[((v_[i] >> 4) & 0xF)];
const char c2 = hexChars[(v_[i] & 0xF)]; const char c2 = hexChars[(v_[i] & 0xF)];
if (c1 != hexdigits[charI] || c2 != hexdigits[charI+1]) if (c1 != hexdigits[charI++]) return false;
{ if (c2 != hexdigits[charI++]) return false;
return false;
}
} }
return true; return true;
@ -230,16 +275,7 @@ Foam::Istream& Foam::operator>>(Istream& is, SHA1Digest& dig)
Foam::Ostream& Foam::operator<<(Ostream& os, const SHA1Digest& dig) Foam::Ostream& Foam::operator<<(Ostream& os, const SHA1Digest& dig)
{ {
const unsigned char *v = dig.v_; return dig.write(os);
for (unsigned i = 0; i < dig.length; ++i)
{
os.write(hexChars[((v[i] >> 4) & 0xF)]);
os.write(hexChars[(v[i] & 0xF)]);
}
os.check("Ostream& operator<<(Ostream&, const SHA1Digest&)");
return os;
} }

View File

@ -46,8 +46,8 @@ namespace Foam
{ {
// Forward declaration of classes // Forward declaration of classes
class Ostream;
class Istream; class Istream;
class Ostream;
// Forward declaration of friend functions and operators // Forward declaration of friend functions and operators
class SHA1; class SHA1;
@ -57,7 +57,7 @@ Istream& operator>>(Istream&, SHA1Digest&);
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class SHA1Digest Declaration Class SHA1Digest Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
class SHA1Digest class SHA1Digest
@ -65,57 +65,89 @@ class SHA1Digest
public: public:
friend class SHA1; friend class SHA1;
//- The length of the digest contents // Static data members
static const unsigned length = 20;
//- Construct a zero digest //- The length of the (uncoded) digest contents
SHA1Digest(); static const unsigned length = 20;
//- Construct read a digest //- A null digest (ie, all zero)
SHA1Digest(Istream&); static const SHA1Digest null;
//- Reset the digest to zero
void clear();
//- Return true if the digest is empty (ie, all zero).
bool empty() const;
//- Return string representation
std::string str() const;
//- Equality operator
bool operator==(const SHA1Digest&) const;
//- Compare to (40-byte) text representation (eg, from sha1sum)
// An %empty string is equivalent to
// "0000000000000000000000000000000000000000"
bool operator==(const std::string& hexdigits) const;
//- Compare to (40-byte) text representation (eg, from sha1sum)
// A %null or %empty string is equivalent to
// "0000000000000000000000000000000000000000"
bool operator==(const char* hexdigits) const;
//- Inequality operator // Constructors
bool operator!=(const SHA1Digest&) const;
//- Inequality operator //- Construct a zero digest
bool operator!=(const std::string& hexdigits) const; SHA1Digest();
//- Inequality operator //- Construct read a digest
bool operator!=(const char* hexdigits) const; SHA1Digest(Istream&);
friend Ostream& operator<<(Ostream&, const SHA1Digest&); // Member Functions
friend Istream& operator>>(Istream&, SHA1Digest&);
//- Reset the digest to zero
void clear();
//- Return true if the digest is empty (ie, all zero).
bool empty() const;
//- Return (40-byte) text representation, optionally with '_' prefix
std::string str(const bool prefixed=false) const;
//- Write (40-byte) text representation, optionally with '_' prefix
Ostream& write(Ostream&, const bool prefixed=false) const;
// Member Operators
//- Equality operator
bool operator==(const SHA1Digest&) const;
//- Compare to (40-byte) text representation (eg, from sha1sum)
// An %empty string is equivalent to
// "0000000000000000000000000000000000000000"
// The hexdigits may optionally start with a '_' prefix
bool operator==(const std::string& hexdigits) const;
//- Compare to (40-byte) text representation (eg, from sha1sum)
// A %null or %empty string is equivalent to
// "0000000000000000000000000000000000000000"
// The hexdigits may optionally start with a '_' prefix
bool operator==(const char* hexdigits) const;
//- Inequality operator
bool operator!=(const SHA1Digest&) const;
//- Inequality operator
bool operator!=(const std::string& hexdigits) const;
//- Inequality operator
bool operator!=(const char* hexdigits) const;
// IOstream Operators
//- Read (40-byte) text representation
// Since leading and intermediate underscores are skipped, a '_' can
// be prefixed to the text representation to use an unquoted
// SHA1Digest without parsing ambiguities as a number.
friend Istream& operator>>(Istream&, SHA1Digest&);
//- Write (40-byte) text representation, unquoted and without prefix
friend Ostream& operator<<(Ostream&, const SHA1Digest&);
private: private:
// Private data
//- The digest contents //- The digest contents
unsigned char v_[length]; unsigned char v_[length];
static unsigned char readHexDigit(Istream&); //- Read hexadecimal value, ignoring leading or intermediate '_'
static unsigned char readHexDigit(Istream&);
}; };