summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/hash.cpp
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2022-04-19 14:22:04 -0400
committer AJR <ajrhacker@users.noreply.github.com>2022-04-19 14:28:45 -0400
commitb45569d964aa8fae416d2049ba70699f5b2d7837 (patch)
tree522b58375072a7b7f3acc36081de7daa9302417d /src/lib/util/hash.cpp
parent7780f53ffd266ad7a88058ecda056e5eeea3bc9f (diff)
File handling cleanup
- Remove fgetc, fgets and ptr methods from device_image_interface. - Remove the core_file::buffer method to read an entire file into memory and rewrite emu_file::hashes to not depend on it. - Make core_in_memory_file a final class; now that buffering is gone, core_osd_file no longer subclasses it but a new superclass that retains some common methods. - Rename the offset and length methods used internally in core_file implementations to index and size due to frequent clashes with parameter names. - Convert comments in util/corefile.cpp to C++ style. - Add a new overload of the hash_collection::compute method which hashes data from a random_read stream, reading it into memory one chunk at a time. As a result, the hash_collection::begin and hash_collection::end methods have been removed as obsolete (similar methods are now used internally only). - Enhance error messages for the frontend media identifier when it encounters file errors.
Diffstat (limited to 'src/lib/util/hash.cpp')
-rw-r--r--src/lib/util/hash.cpp160
1 files changed, 92 insertions, 68 deletions
diff --git a/src/lib/util/hash.cpp b/src/lib/util/hash.cpp
index a521e737192..8cdf41ba0e9 100644
--- a/src/lib/util/hash.cpp
+++ b/src/lib/util/hash.cpp
@@ -12,8 +12,11 @@
#include "hash.h"
+#include "ioprocs.h"
+
#include <cassert>
#include <cctype>
+#include <optional>
namespace util {
@@ -27,48 +30,68 @@ char const *const hash_collection::HASH_TYPES_CRC_SHA1 = "RS";
char const *const hash_collection::HASH_TYPES_ALL = "RS";
-
//**************************************************************************
-// 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)
+ {
+ 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)
+ {
+ // 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(std::string_view string)
- : m_has_crc32(false),
- m_has_sha1(false),
- m_creator(nullptr)
-{
- from_internal_string(string);
-}
+ // stop hashing
+ void finish(hash_collection &hashes)
+ {
+ // 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;
}
@@ -138,8 +161,6 @@ void hash_collection::reset()
{
m_flags.clear();
m_has_crc32 = m_has_sha1 = false;
- delete m_creator;
- m_creator = nullptr;
}
@@ -336,69 +357,75 @@ bool hash_collection::from_internal_string(std::string_view 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);
- // 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);
+ // run the hashes
+ 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
+ std::size_t bytes_read;
+ std::error_condition err = stream.read_at(offset, buffer, chunk_length, bytes_read);
+ if (err)
+ return err;
+ if (!bytes_read) // EOF?
+ break;
+ offset += bytes_read;
+ length -= chunk_length;
+
+ // 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