diff options
Diffstat (limited to 'src/lib/util/hash.cpp')
-rw-r--r-- | src/lib/util/hash.cpp | 226 |
1 files changed, 125 insertions, 101 deletions
diff --git a/src/lib/util/hash.cpp b/src/lib/util/hash.cpp index ddb6f52ac5c..f2c528e9b22 100644 --- a/src/lib/util/hash.cpp +++ b/src/lib/util/hash.cpp @@ -11,68 +11,87 @@ ***************************************************************************/ #include "hash.h" -#include "hashing.h" -#include <ctype.h> + +#include "ioprocs.h" + +#include <cassert> +#include <cctype> +#include <optional> namespace util { + //************************************************************************** // GLOBAL VARIABLES //************************************************************************** -char const hash_collection::HASH_CRC; -char const hash_collection::HASH_SHA1; - char const *const hash_collection::HASH_TYPES_CRC = "R"; char const *const hash_collection::HASH_TYPES_CRC_SHA1 = "RS"; char const *const hash_collection::HASH_TYPES_ALL = "RS"; -char const hash_collection::FLAG_NO_DUMP; -char const hash_collection::FLAG_BAD_DUMP; - - //************************************************************************** -// HASH COLLECTION +// HASH CREATOR //************************************************************************** -//------------------------------------------------- -// hash_collection - constructor -//------------------------------------------------- - -hash_collection::hash_collection() - : m_has_crc32(false), - m_has_sha1(false), - m_creator(nullptr) +class hash_collection::hash_creator { -} +public: + // constructor + hash_creator(bool doing_crc32, bool doing_sha1) noexcept + { + if (doing_crc32) + m_crc32_creator.emplace(); + if (doing_sha1) + m_sha1_creator.emplace(); + } + // add the given buffer to the hash + void append(void const *buffer, std::size_t length) noexcept + { + // append to each active hash + if (m_crc32_creator) + m_crc32_creator->append(buffer, length); + if (m_sha1_creator) + m_sha1_creator->append(buffer, length); + } -hash_collection::hash_collection(const char *string) - : m_has_crc32(false), - m_has_sha1(false), - m_creator(nullptr) -{ - from_internal_string(string); -} + // stop hashing + void finish(hash_collection &hashes) noexcept + { + // finish up the CRC32 + if (m_crc32_creator) + { + hashes.add_crc(m_crc32_creator->finish()); + m_crc32_creator.reset(); + } + // finish up the SHA1 + if (m_sha1_creator) + { + hashes.add_sha1(m_sha1_creator->finish()); + m_sha1_creator.reset(); + } + } -hash_collection::hash_collection(const hash_collection &src) - : m_has_crc32(false), - m_has_sha1(false), - m_creator(nullptr) -{ - copyfrom(src); -} +private: + std::optional<crc32_creator> m_crc32_creator; + std::optional<sha1_creator> m_sha1_creator; +}; +//************************************************************************** +// HASH COLLECTION +//************************************************************************** + //------------------------------------------------- -// ~hash_collection - destructor +// hash_collection - constructor //------------------------------------------------- -hash_collection::~hash_collection() +hash_collection::hash_collection() + : m_has_crc32(false) + , m_has_sha1(false) { - delete m_creator; } @@ -93,15 +112,16 @@ hash_collection &hash_collection::operator=(const hash_collection &src) // operator== - test for equality //------------------------------------------------- -bool hash_collection::operator==(const hash_collection &rhs) const +bool hash_collection::operator==(const hash_collection &rhs) const noexcept { + bool matches = false; + // match CRCs - int matches = 0; if (m_has_crc32 && rhs.m_has_crc32) { if (m_crc32 != rhs.m_crc32) return false; - matches++; + matches = true; } // match SHA1s @@ -109,11 +129,11 @@ bool hash_collection::operator==(const hash_collection &rhs) const { if (m_sha1 != rhs.m_sha1) return false; - matches++; + matches = true; } - // if all shared hashes match, return true - return (matches > 0); + // if at least one type is shared and matches, return true + return matches; } @@ -138,12 +158,10 @@ std::string hash_collection::hash_types() const // set of hashes and flags //------------------------------------------------- -void hash_collection::reset() +void hash_collection::reset() noexcept { m_flags.clear(); m_has_crc32 = m_has_sha1 = false; - delete m_creator; - m_creator = nullptr; } @@ -152,15 +170,15 @@ void hash_collection::reset() // from a string //------------------------------------------------- -bool hash_collection::add_from_string(char type, const char *buffer, int length) +bool hash_collection::add_from_string(char type, std::string_view string) noexcept { // handle CRCs if (type == HASH_CRC) - return m_has_crc32 = m_crc32.from_string(buffer, length); + return m_has_crc32 = m_crc32.from_string(string); // handle SHA1s else if (type == HASH_SHA1) - return m_has_sha1 = m_sha1.from_string(buffer, length); + return m_has_sha1 = m_sha1.from_string(string); return false; } @@ -170,7 +188,7 @@ bool hash_collection::add_from_string(char type, const char *buffer, int length) // remove - remove a hash of the given type //------------------------------------------------- -bool hash_collection::remove(char type) +bool hash_collection::remove(char type) noexcept { bool result = false; @@ -240,7 +258,13 @@ std::string hash_collection::macro_string() const buffer.append("NO_DUMP "); if (flag(FLAG_BAD_DUMP)) buffer.append("BAD_DUMP "); - strtrimspace(buffer); + + // remove trailing space + if (!buffer.empty()) + { + assert(buffer.back() == ' '); + buffer = buffer.substr(0, buffer.length() - 1); + } return buffer; } @@ -267,7 +291,10 @@ std::string hash_collection::attribute_string() const buffer.append("status=\"nodump\""); if (flag(FLAG_BAD_DUMP)) buffer.append("status=\"baddump\""); - strtrimspace(buffer); + + // remove trailing space + if (!buffer.empty() && buffer.back() == ' ') + buffer = buffer.substr(0, buffer.length() - 1); return buffer; } @@ -277,24 +304,19 @@ std::string hash_collection::attribute_string() const // compact string to set of hashes and flags //------------------------------------------------- -bool hash_collection::from_internal_string(const char *string) +bool hash_collection::from_internal_string(std::string_view string) { - assert(string != nullptr); - // start fresh reset(); - // determine the end of the string - const char *stringend = string + strlen(string); - const char *ptr = string; - - // loop until we hit it + // loop until we hit the end of the string bool errors = false; int skip_digits = 0; - while (ptr < stringend) + while (!string.empty()) { - char c = *ptr++; + char c = string[0]; char uc = toupper(c); + string.remove_prefix(1); // non-hex alpha values specify a hash type if (uc >= 'G' && uc <= 'Z') @@ -303,13 +325,13 @@ bool hash_collection::from_internal_string(const char *string) if (uc == HASH_CRC) { m_has_crc32 = true; - errors = !m_crc32.from_string(ptr, stringend - ptr); + errors = !m_crc32.from_string(string); skip_digits = 2 * sizeof(crc32_t); } else if (uc == HASH_SHA1) { m_has_sha1 = true; - errors = !m_sha1.from_string(ptr, stringend - ptr); + errors = !m_sha1.from_string(string); skip_digits = 2 * sizeof(sha1_t); } else @@ -336,69 +358,74 @@ bool hash_collection::from_internal_string(const char *string) //------------------------------------------------- -// begin - begin hashing +// create - begin hashing //------------------------------------------------- -void hash_collection::begin(const char *types) +std::unique_ptr<hash_collection::hash_creator> hash_collection::create(const char *types) { - // nuke previous creator and make a new one - delete m_creator; - m_creator = new hash_creator; - // by default use all types if (types == nullptr) - m_creator->m_doing_crc32 = m_creator->m_doing_sha1 = true; + return std::make_unique<hash_creator>(true, true); // otherwise, just allocate the ones that are specified else - { - m_creator->m_doing_crc32 = (strchr(types, HASH_CRC) != nullptr); - m_creator->m_doing_sha1 = (strchr(types, HASH_SHA1) != nullptr); - } + return std::make_unique<hash_creator>(strchr(types, HASH_CRC) != nullptr, strchr(types, HASH_SHA1) != nullptr); } //------------------------------------------------- -// buffer - add the given buffer to the hash +// compute - hash a block of data //------------------------------------------------- -void hash_collection::buffer(const uint8_t *data, uint32_t length) +void hash_collection::compute(const uint8_t *data, uint32_t length, const char *types) { - assert(m_creator != nullptr); + // begin + std::unique_ptr<hash_creator> creator = create(types); + + // run the hashes + creator->append(data, length); - // append to each active hash - if (m_creator->m_doing_crc32) - m_creator->m_crc32_creator.append(data, length); - if (m_creator->m_doing_sha1) - m_creator->m_sha1_creator.append(data, length); + // end + creator->finish(*this); } //------------------------------------------------- -// end - stop hashing +// compute - hash data from a stream //------------------------------------------------- -void hash_collection::end() +std::error_condition hash_collection::compute(random_read &stream, uint64_t offset, size_t length, size_t &actual, const char *types) { - assert(m_creator != nullptr); + // begin + std::unique_ptr<hash_creator> creator = create(types); - // finish up the CRC32 - if (m_creator->m_doing_crc32) - { - m_has_crc32 = true; - m_crc32 = m_creator->m_crc32_creator.finish(); - } + // local buffer of arbitrary size + uint8_t buffer[2048]; - // finish up the SHA1 - if (m_creator->m_doing_sha1) + // run the hashes + actual = 0U; + while (length) { - m_has_sha1 = true; - m_sha1 = m_creator->m_sha1_creator.finish(); + // determine the size of the next chunk + unsigned const chunk_length = std::min(length, sizeof(buffer)); + + // read one chunk + auto const [err, bytes_read] = read_at(stream, offset, buffer, chunk_length); + if (err) + return err; + if (!bytes_read) // EOF? + break; + offset += bytes_read; + length -= bytes_read; + + // append the chunk + creator->append(buffer, bytes_read); + actual += bytes_read; } - // nuke the creator - delete m_creator; - m_creator = nullptr; + // end + creator->finish(*this); + return std::error_condition(); } @@ -417,9 +444,6 @@ void hash_collection::copyfrom(const hash_collection &src) m_crc32 = src.m_crc32; m_has_sha1 = src.m_has_sha1; m_sha1 = src.m_sha1; - - // don't copy creators - m_creator = nullptr; } } // namespace util |