/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "SHA1Digest.H" #include "IOstreams.H" #include // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // const Foam::SHA1Digest Foam::SHA1Digest::null; static const char hexChars[] = "0123456789abcdef"; // The char '0' == 0 static constexpr int offsetZero = int('0'); // The char 'A' (or 'a') == 10 static constexpr int offsetUpper = int('A') - 10; // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // namespace Foam { // Read hexadecimal value, ignoring leading or intermediate '_' static unsigned char readHexDigit(Istream& is) { // Silently ignore leading or intermediate '_' char c = 0; do { is.read(c); } while (c == '_'); if (isdigit(c)) { return int(c) - offsetZero; } else if (!isxdigit(c)) { FatalIOErrorInFunction(is) << "Illegal hex digit: '" << c << "'" << exit(FatalIOError); } return toupper(c) - offsetUpper; } } // End namespace Foam // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::SHA1Digest::SHA1Digest() { clear(); } Foam::SHA1Digest::SHA1Digest(Istream& is) { clear(); read(is); } // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // void Foam::SHA1Digest::clear() { dig_.fill(0); // Same as memset(dig_.data(), 0, dig_.size()); } bool Foam::SHA1Digest::empty() const { for (const auto& byteVal : dig_) { if (byteVal) { return false; } } return true; } std::string Foam::SHA1Digest::str(const bool prefixed) const { std::string buf; unsigned nChar = 0; if (prefixed) { buf.resize(1 + 2*dig_.size()); buf[nChar++] = '_'; } else { buf.resize(2*dig_.size()); } for (const auto& byteVal : dig_) { buf[nChar++] = hexChars[((byteVal >> 4) & 0xF)]; // Upper nibble buf[nChar++] = hexChars[(byteVal & 0xF)]; // Lower nibble } return buf; } Foam::Istream& Foam::SHA1Digest::read(Istream& is) { for (auto& byteVal : dig_) { const unsigned char upp = readHexDigit(is); const unsigned char low = readHexDigit(is); byteVal = (upp << 4) + low; } is.check(FUNCTION_NAME); return is; } Foam::Ostream& Foam::SHA1Digest::write(Ostream& os, const bool prefixed) const { if (prefixed) { os.write('_'); } for (const auto& byteVal : dig_) { os.write(hexChars[((byteVal >> 4) & 0xF)]); // Upper nibble os.write(hexChars[(byteVal & 0xF)]); // Lower nibble } os.check(FUNCTION_NAME); return os; } // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * // bool Foam::SHA1Digest::operator==(const SHA1Digest& rhs) const { return (dig_ == rhs.dig_); } bool Foam::SHA1Digest::operator==(const std::string& hexdigits) const { // Null or empty string is not an error - interpret as '0000..' if (hexdigits.empty()) { return empty(); } // Skip possible '_' prefix unsigned nChar = 0; if (hexdigits[0] == '_') { ++nChar; } // Incorrect length - can never match if (hexdigits.size() != nChar + 2*dig_.size()) { return false; } for (const auto& byteVal : dig_) { const char upp = hexChars[((byteVal >> 4) & 0xF)]; // Upper nibble const char low = hexChars[(byteVal & 0xF)]; // Lower nibble if (upp != hexdigits[nChar++]) return false; if (low != hexdigits[nChar++]) return false; } return true; } bool Foam::SHA1Digest::operator==(const char* hexdigits) const { // Null or empty string is not an error - interpret as '0000..' if (!hexdigits || !*hexdigits) { return empty(); } // Skip possible '_' prefix unsigned nChar = 0; if (hexdigits[0] == '_') { ++nChar; } // Incorrect length - can never match if (strlen(hexdigits) != nChar + 2*dig_.size()) { return false; } for (const auto& byteVal : dig_) { const char upp = hexChars[((byteVal >> 4) & 0xF)]; const char low = hexChars[(byteVal & 0xF)]; if (upp != hexdigits[nChar++]) return false; if (low != hexdigits[nChar++]) return false; } return true; } bool Foam::SHA1Digest::operator!=(const SHA1Digest& rhs) const { return !operator==(rhs); } bool Foam::SHA1Digest::operator!=(const std::string& rhs) const { return !operator==(rhs); } bool Foam::SHA1Digest::operator!=(const char* rhs) const { return !operator==(rhs); } // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // Foam::Istream& Foam::operator>>(Istream& is, SHA1Digest& dig) { return dig.read(is); } Foam::Ostream& Foam::operator<<(Ostream& os, const SHA1Digest& dig) { return dig.write(os); } // ************************************************************************* //