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

@ -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] );

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;
do
{
is.read(c); 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;
@ -65,23 +65,40 @@ class SHA1Digest
public: public:
friend class SHA1; friend class SHA1;
//- The length of the digest contents // Static data members
//- The length of the (uncoded) digest contents
static const unsigned length = 20; static const unsigned length = 20;
//- A null digest (ie, all zero)
static const SHA1Digest null;
// Constructors
//- Construct a zero digest //- Construct a zero digest
SHA1Digest(); SHA1Digest();
//- Construct read a digest //- Construct read a digest
SHA1Digest(Istream&); SHA1Digest(Istream&);
// Member Functions
//- Reset the digest to zero //- Reset the digest to zero
void clear(); void clear();
//- Return true if the digest is empty (ie, all zero). //- Return true if the digest is empty (ie, all zero).
bool empty() const; bool empty() const;
//- Return string representation //- Return (40-byte) text representation, optionally with '_' prefix
std::string str() const; 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 //- Equality operator
bool operator==(const SHA1Digest&) const; bool operator==(const SHA1Digest&) const;
@ -89,11 +106,13 @@ public:
//- Compare to (40-byte) text representation (eg, from sha1sum) //- Compare to (40-byte) text representation (eg, from sha1sum)
// An %empty string is equivalent to // An %empty string is equivalent to
// "0000000000000000000000000000000000000000" // "0000000000000000000000000000000000000000"
// The hexdigits may optionally start with a '_' prefix
bool operator==(const std::string& hexdigits) const; bool operator==(const std::string& hexdigits) const;
//- Compare to (40-byte) text representation (eg, from sha1sum) //- Compare to (40-byte) text representation (eg, from sha1sum)
// A %null or %empty string is equivalent to // A %null or %empty string is equivalent to
// "0000000000000000000000000000000000000000" // "0000000000000000000000000000000000000000"
// The hexdigits may optionally start with a '_' prefix
bool operator==(const char* hexdigits) const; bool operator==(const char* hexdigits) const;
@ -107,14 +126,27 @@ public:
bool operator!=(const char* hexdigits) const; bool operator!=(const char* hexdigits) const;
friend Ostream& operator<<(Ostream&, const SHA1Digest&);
// 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&); 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];
//- Read hexadecimal value, ignoring leading or intermediate '_'
static unsigned char readHexDigit(Istream&); static unsigned char readHexDigit(Istream&);
}; };