diff options
Diffstat (limited to 'src/lib/util')
-rw-r--r-- | src/lib/util/chd.cpp | 100 | ||||
-rw-r--r-- | src/lib/util/chd.h | 36 | ||||
-rw-r--r-- | src/lib/util/hash.cpp | 423 | ||||
-rw-r--r-- | src/lib/util/hash.h | 122 | ||||
-rw-r--r-- | src/lib/util/hashing.cpp | 3 | ||||
-rw-r--r-- | src/lib/util/hashing.h | 3 |
6 files changed, 619 insertions, 68 deletions
diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp index 55bc313102a..fd6f1c5ad1a 100644 --- a/src/lib/util/chd.cpp +++ b/src/lib/util/chd.cpp @@ -115,7 +115,7 @@ struct chd_file::metadata_entry struct chd_file::metadata_hash { UINT8 tag[4]; // tag of the metadata in big-endian - sha1_t sha1; // hash data + util::sha1_t sha1; // hash data }; @@ -159,9 +159,9 @@ inline void chd_file::be_write(UINT8 *base, UINT64 value, int numbytes) // stream in bigendian order //------------------------------------------------- -inline sha1_t chd_file::be_read_sha1(const UINT8 *base) +inline util::sha1_t chd_file::be_read_sha1(const UINT8 *base) { - sha1_t result; + util::sha1_t result; memcpy(&result.m_raw[0], base, sizeof(result.m_raw)); return result; } @@ -172,7 +172,7 @@ inline sha1_t chd_file::be_read_sha1(const UINT8 *base) // stream in bigendian order //------------------------------------------------- -inline void chd_file::be_write_sha1(UINT8 *base, sha1_t value) +inline void chd_file::be_write_sha1(UINT8 *base, util::sha1_t value) { memcpy(base, &value.m_raw[0], sizeof(value.m_raw)); } @@ -311,7 +311,7 @@ chd_file::~chd_file() } /** - * @fn sha1_t chd_file::sha1() + * @fn util::sha1_t chd_file::sha1() * * @brief ------------------------------------------------- * sha1 - return our SHA1 value @@ -320,24 +320,24 @@ chd_file::~chd_file() * @return A sha1_t. */ -sha1_t chd_file::sha1() +util::sha1_t chd_file::sha1() { try { // read the big-endian version - UINT8 rawbuf[sizeof(sha1_t)]; + UINT8 rawbuf[sizeof(util::sha1_t)]; file_read(m_sha1_offset, rawbuf, sizeof(rawbuf)); return be_read_sha1(rawbuf); } catch (chd_error &) { // on failure, return nullptr - return sha1_t::null; + return util::sha1_t::null; } } /** - * @fn sha1_t chd_file::raw_sha1() + * @fn util::sha1_t chd_file::raw_sha1() * * @brief ------------------------------------------------- * raw_sha1 - return our raw SHA1 value @@ -349,7 +349,7 @@ sha1_t chd_file::sha1() * @return A sha1_t. */ -sha1_t chd_file::raw_sha1() +util::sha1_t chd_file::raw_sha1() { try { @@ -358,19 +358,19 @@ sha1_t chd_file::raw_sha1() throw CHDERR_UNSUPPORTED_VERSION; // read the big-endian version - UINT8 rawbuf[sizeof(sha1_t)]; + UINT8 rawbuf[sizeof(util::sha1_t)]; file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf)); return be_read_sha1(rawbuf); } catch (chd_error &) { // on failure, return nullptr - return sha1_t::null; + return util::sha1_t::null; } } /** - * @fn sha1_t chd_file::parent_sha1() + * @fn util::sha1_t chd_file::parent_sha1() * * @brief ------------------------------------------------- * parent_sha1 - return our parent's SHA1 value @@ -382,7 +382,7 @@ sha1_t chd_file::raw_sha1() * @return A sha1_t. */ -sha1_t chd_file::parent_sha1() +util::sha1_t chd_file::parent_sha1() { try { @@ -391,14 +391,14 @@ sha1_t chd_file::parent_sha1() throw CHDERR_UNSUPPORTED_VERSION; // read the big-endian version - UINT8 rawbuf[sizeof(sha1_t)]; + UINT8 rawbuf[sizeof(util::sha1_t)]; file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf)); return be_read_sha1(rawbuf); } catch (chd_error &) { // on failure, return nullptr - return sha1_t::null; + return util::sha1_t::null; } } @@ -523,10 +523,10 @@ chd_error chd_file::hunk_info(UINT32 hunknum, chd_codec_type &compressor, UINT32 * @param rawdata The rawdata. */ -void chd_file::set_raw_sha1(sha1_t rawdata) +void chd_file::set_raw_sha1(util::sha1_t rawdata) { // create a big-endian version - UINT8 rawbuf[sizeof(sha1_t)]; + UINT8 rawbuf[sizeof(util::sha1_t)]; be_write_sha1(rawbuf, rawdata); // write to the header @@ -551,14 +551,14 @@ void chd_file::set_raw_sha1(sha1_t rawdata) * @param parent The parent. */ -void chd_file::set_parent_sha1(sha1_t parent) +void chd_file::set_parent_sha1(util::sha1_t parent) { // if no file, fail if (m_file == nullptr) throw CHDERR_INVALID_FILE; // create a big-endian version - UINT8 rawbuf[sizeof(sha1_t)]; + UINT8 rawbuf[sizeof(util::sha1_t)]; be_write_sha1(rawbuf, parent); // write to the header @@ -902,13 +902,13 @@ chd_error chd_file::read_hunk(UINT32 hunknum, void *buffer) blocklen = be_read(&rawmap[12], 2) + (rawmap[14] << 16); file_read(blockoffs, &m_compressed[0], blocklen); m_decompressor[0]->decompress(&m_compressed[0], blocklen, dest, m_hunkbytes); - if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != nullptr && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) + if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != nullptr && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: file_read(blockoffs, dest, m_hunkbytes); - if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) + if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; @@ -916,7 +916,7 @@ chd_error chd_file::read_hunk(UINT32 hunknum, void *buffer) be_write(dest, blockoffs, 8); for (UINT32 bytes = 8; bytes < m_hunkbytes; bytes++) dest[bytes] = dest[bytes - 8]; - if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) + if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && util::crc32_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; @@ -961,15 +961,15 @@ chd_error chd_file::read_hunk(UINT32 hunknum, void *buffer) case COMPRESSION_TYPE_3: file_read(blockoffs, &m_compressed[0], blocklen); m_decompressor[rawmap[0]]->decompress(&m_compressed[0], blocklen, dest, m_hunkbytes); - if (!m_decompressor[rawmap[0]]->lossy() && dest != nullptr && crc16_creator::simple(dest, m_hunkbytes) != blockcrc) + if (!m_decompressor[rawmap[0]]->lossy() && dest != nullptr && util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; - if (m_decompressor[rawmap[0]]->lossy() && crc16_creator::simple(&m_compressed[0], blocklen) != blockcrc) + if (m_decompressor[rawmap[0]]->lossy() && util::crc16_creator::simple(&m_compressed[0], blocklen) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case COMPRESSION_NONE: file_read(blockoffs, dest, m_hunkbytes); - if (crc16_creator::simple(dest, m_hunkbytes) != blockcrc) + if (util::crc16_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; @@ -1558,7 +1558,7 @@ chd_error chd_file::clone_all_metadata(chd_file &source) } /** - * @fn sha1_t chd_file::compute_overall_sha1(sha1_t rawsha1) + * @fn util::sha1_t chd_file::compute_overall_sha1(sha1_t rawsha1) * * @brief ------------------------------------------------- * compute_overall_sha1 - iterate through the metadata and compute the overall hash of @@ -1570,7 +1570,7 @@ chd_error chd_file::clone_all_metadata(chd_file &source) * @return The calculated overall sha 1. */ -sha1_t chd_file::compute_overall_sha1(sha1_t rawsha1) +util::sha1_t chd_file::compute_overall_sha1(util::sha1_t rawsha1) { // only works for v4 and above if (m_version < 4) @@ -1593,7 +1593,7 @@ sha1_t chd_file::compute_overall_sha1(sha1_t rawsha1) // create an entry for this metadata and add it metadata_hash hashentry; be_write(hashentry.tag, metaentry.metatag, 4); - hashentry.sha1 = sha1_creator::simple(&filedata[0], metaentry.length); + hashentry.sha1 = util::sha1_creator::simple(&filedata[0], metaentry.length); hasharray.push_back(hashentry); } @@ -1602,7 +1602,7 @@ sha1_t chd_file::compute_overall_sha1(sha1_t rawsha1) qsort(&hasharray[0], hasharray.size(), sizeof(hasharray[0]), metadata_hash_compare); // read the raw data hash from our header and start a new SHA1 with that data - sha1_creator overall_sha1; + util::sha1_creator overall_sha1; overall_sha1.append(&rawsha1, sizeof(rawsha1)); if (!hasharray.empty()) overall_sha1.append(&hasharray[0], hasharray.size() * sizeof(hasharray[0])); @@ -1750,7 +1750,7 @@ UINT32 chd_file::guess_unitbytes() * @param [in,out] parentsha1 The first parentsha. */ -void chd_file::parse_v3_header(UINT8 *rawheader, sha1_t &parentsha1) +void chd_file::parse_v3_header(UINT8 *rawheader, util::sha1_t &parentsha1) { // verify header length if (be_read(&rawheader[8], 4) != V3_HEADER_SIZE) @@ -1813,7 +1813,7 @@ void chd_file::parse_v3_header(UINT8 *rawheader, sha1_t &parentsha1) * @param [in,out] parentsha1 The first parentsha. */ -void chd_file::parse_v4_header(UINT8 *rawheader, sha1_t &parentsha1) +void chd_file::parse_v4_header(UINT8 *rawheader, util::sha1_t &parentsha1) { // verify header length if (be_read(&rawheader[8], 4) != V4_HEADER_SIZE) @@ -1873,7 +1873,7 @@ void chd_file::parse_v4_header(UINT8 *rawheader, sha1_t &parentsha1) * @param [in,out] parentsha1 The first parentsha. */ -void chd_file::parse_v5_header(UINT8 *rawheader, sha1_t &parentsha1) +void chd_file::parse_v5_header(UINT8 *rawheader, util::sha1_t &parentsha1) { // verify header length if (be_read(&rawheader[8], 4) != V5_HEADER_SIZE) @@ -1928,7 +1928,7 @@ chd_error chd_file::compress_v5_map() try { // first get a CRC-16 of the original rawmap - crc16_t mapcrc = crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12); + util::crc16_t mapcrc = util::crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12); // create a buffer to hold the RLE data dynamic_buffer compression_rle(m_hunkcount); @@ -2244,7 +2244,7 @@ void chd_file::decompress_v5_map() } // verify the final CRC - if (crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12) != mapcrc) + if (util::crc16_creator::simple(&m_rawmap[0], m_hunkcount * 12) != mapcrc) throw CHDERR_DECOMPRESSION_ERROR; } @@ -2310,15 +2310,15 @@ chd_error chd_file::create_common() be_write(&rawheader[48], m_metaoffset, 8); be_write(&rawheader[56], m_hunkbytes, 4); be_write(&rawheader[60], m_unitbytes, 4); - be_write_sha1(&rawheader[64], sha1_t::null); - be_write_sha1(&rawheader[84], sha1_t::null); - be_write_sha1(&rawheader[104], (m_parent != nullptr) ? m_parent->sha1() : sha1_t::null); + be_write_sha1(&rawheader[64], util::sha1_t::null); + be_write_sha1(&rawheader[84], util::sha1_t::null); + be_write_sha1(&rawheader[104], (m_parent != nullptr) ? m_parent->sha1() : util::sha1_t::null); // write the resulting header file_write(0, rawheader, sizeof(rawheader)); // parse it back out to set up fields appropriately - sha1_t parentsha1; + util::sha1_t parentsha1; parse_v5_header(rawheader, parentsha1); // writes are obviously permitted; reads only if uncompressed @@ -2403,7 +2403,7 @@ chd_error chd_file::open_common(bool writeable) throw CHDERR_UNSUPPORTED_VERSION; // read the header if we support it - sha1_t parentsha1 = sha1_t::null; + util::sha1_t parentsha1 = util::sha1_t::null; switch (m_version) { case 3: parse_v3_header(rawheader, parentsha1); break; @@ -2416,7 +2416,7 @@ chd_error chd_file::open_common(bool writeable) throw CHDERR_FILE_NOT_WRITEABLE; // make sure we have a parent if we need one (and don't if we don't) - if (parentsha1 != sha1_t::null) + if (parentsha1 != util::sha1_t::null) { if (m_parent == nullptr) m_parent_missing = true; @@ -2535,7 +2535,7 @@ void chd_file::verify_proper_compression_append(UINT32 hunknum) * @param crc16 The CRC 16. */ -void chd_file::hunk_write_compressed(UINT32 hunknum, INT8 compression, const UINT8 *compressed, UINT32 complength, crc16_t crc16) +void chd_file::hunk_write_compressed(UINT32 hunknum, INT8 compression, const UINT8 *compressed, UINT32 complength, util::crc16_t crc16) { // verify that we are appending properly to a compressed file verify_proper_compression_append(hunknum); @@ -2711,10 +2711,10 @@ void chd_file::metadata_update_hash() return; // compute the new overall hash - sha1_t fullsha1 = compute_overall_sha1(raw_sha1()); + util::sha1_t fullsha1 = compute_overall_sha1(raw_sha1()); // create a big-endian version - UINT8 rawbuf[sizeof(sha1_t)]; + UINT8 rawbuf[sizeof(util::sha1_t)]; be_write_sha1(&rawbuf[0], fullsha1); // write to the header @@ -3033,8 +3033,8 @@ void chd_file_compressor::async_walk_parent(work_item &item) units = 1; for (UINT32 unit = 0; unit < units; unit++) { - item.m_hash[unit].m_crc16 = crc16_creator::simple(item.m_data + unit * unit_bytes(), hunk_bytes()); - item.m_hash[unit].m_sha1 = sha1_creator::simple(item.m_data + unit * unit_bytes(), hunk_bytes()); + item.m_hash[unit].m_crc16 = util::crc16_creator::simple(item.m_data + unit * unit_bytes(), hunk_bytes()); + item.m_hash[unit].m_sha1 = util::sha1_creator::simple(item.m_data + unit * unit_bytes(), hunk_bytes()); } item.m_status = WS_COMPLETE; } @@ -3075,8 +3075,8 @@ void chd_file_compressor::async_compress_hunk(work_item &item, int threadid) item.m_codecs = m_codecs[threadid]; // compute CRC-16 and SHA-1 hashes - item.m_hash[0].m_crc16 = crc16_creator::simple(item.m_data, hunk_bytes()); - item.m_hash[0].m_sha1 = sha1_creator::simple(item.m_data, hunk_bytes()); + item.m_hash[0].m_crc16 = util::crc16_creator::simple(item.m_data, hunk_bytes()); + item.m_hash[0].m_sha1 = util::sha1_creator::simple(item.m_data, hunk_bytes()); // find the best compression scheme, unless we already have a self or parent match // (note we may miss a self match from blocks not yet added, but this just results in extra work) @@ -3254,7 +3254,7 @@ void chd_file_compressor::hashmap::reset() * @return An UINT64. */ -UINT64 chd_file_compressor::hashmap::find(crc16_t crc16, sha1_t sha1) +UINT64 chd_file_compressor::hashmap::find(util::crc16_t crc16, util::sha1_t sha1) { // look up the entry in the map for (entry_t *entry = m_map[crc16]; entry != nullptr; entry = entry->m_next) @@ -3275,7 +3275,7 @@ UINT64 chd_file_compressor::hashmap::find(crc16_t crc16, sha1_t sha1) * @param sha1 The first sha. */ -void chd_file_compressor::hashmap::add(UINT64 itemnum, crc16_t crc16, sha1_t sha1) +void chd_file_compressor::hashmap::add(UINT64 itemnum, util::crc16_t crc16, util::sha1_t sha1) { // add to the appropriate map if (m_block_list->m_nextalloc == ARRAY_LENGTH(m_block_list->m_array)) diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index a3b0e0c7304..b0eb4143374 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -317,14 +317,14 @@ public: bool compressed() const { return (m_compression[0] != CHD_CODEC_NONE); } chd_codec_type compression(int index) const { return m_compression[index]; } chd_file *parent() const { return m_parent; } - sha1_t sha1(); - sha1_t raw_sha1(); - sha1_t parent_sha1(); + util::sha1_t sha1(); + util::sha1_t raw_sha1(); + util::sha1_t parent_sha1(); chd_error hunk_info(UINT32 hunknum, chd_codec_type &compressor, UINT32 &compbytes); // setters - void set_raw_sha1(sha1_t rawdata); - void set_parent_sha1(sha1_t parent); + void set_raw_sha1(util::sha1_t rawdata); + void set_parent_sha1(util::sha1_t parent); // file create chd_error create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 unitbytes, chd_codec_type compression[4]); @@ -359,7 +359,7 @@ public: chd_error clone_all_metadata(chd_file &source); // hashing helper - sha1_t compute_overall_sha1(sha1_t rawsha1); + util::sha1_t compute_overall_sha1(util::sha1_t rawsha1); // codec interfaces chd_error codec_configure(chd_codec_type codec, int param, void *config); @@ -374,8 +374,8 @@ private: // inline helpers UINT64 be_read(const UINT8 *base, int numbytes); void be_write(UINT8 *base, UINT64 value, int numbytes); - sha1_t be_read_sha1(const UINT8 *base); - void be_write_sha1(UINT8 *base, sha1_t value); + util::sha1_t be_read_sha1(const UINT8 *base); + void be_write_sha1(UINT8 *base, util::sha1_t value); void file_read(UINT64 offset, void *dest, UINT32 length); void file_write(UINT64 offset, const void *source, UINT32 length); UINT64 file_append(const void *source, UINT32 length, UINT32 alignment = 0); @@ -383,16 +383,16 @@ private: // internal helpers UINT32 guess_unitbytes(); - void parse_v3_header(UINT8 *rawheader, sha1_t &parentsha1); - void parse_v4_header(UINT8 *rawheader, sha1_t &parentsha1); - void parse_v5_header(UINT8 *rawheader, sha1_t &parentsha1); + void parse_v3_header(UINT8 *rawheader, util::sha1_t &parentsha1); + void parse_v4_header(UINT8 *rawheader, util::sha1_t &parentsha1); + void parse_v5_header(UINT8 *rawheader, util::sha1_t &parentsha1); chd_error compress_v5_map(); void decompress_v5_map(); chd_error create_common(); chd_error open_common(bool writeable); void create_open_common(); void verify_proper_compression_append(UINT32 hunknum); - void hunk_write_compressed(UINT32 hunknum, INT8 compression, const UINT8 *compressed, UINT32 complength, crc16_t crc16); + void hunk_write_compressed(UINT32 hunknum, INT8 compression, const UINT8 *compressed, UINT32 complength, util::crc16_t crc16); void hunk_copy_from_self(UINT32 hunknum, UINT32 otherhunk); void hunk_copy_from_parent(UINT32 hunknum, UINT64 parentunit); bool metadata_find(chd_metadata_tag metatag, INT32 metaindex, metadata_entry &metaentry, bool resume = false); @@ -469,8 +469,8 @@ private: // operations void reset(); - UINT64 find(crc16_t crc16, sha1_t sha1); - void add(UINT64 itemnum, crc16_t crc16, sha1_t sha1); + UINT64 find(util::crc16_t crc16, util::sha1_t sha1); + void add(UINT64 itemnum, util::crc16_t crc16, util::sha1_t sha1); // constants static const UINT64 NOT_FOUND = ~UINT64(0); @@ -480,7 +480,7 @@ private: { entry_t * m_next; // next entry in list UINT64 m_itemnum; // item number - sha1_t m_sha1; // SHA-1 of the block + util::sha1_t m_sha1; // SHA-1 of the block }; // block of entries @@ -511,8 +511,8 @@ private: // a CRC-16/SHA-1 pair struct hash_pair { - crc16_t m_crc16; // calculated CRC-16 - sha1_t m_sha1; // calculated SHA-1 + util::crc16_t m_crc16; // calculated CRC-16 + util::sha1_t m_sha1; // calculated SHA-1 }; // a single work item @@ -556,7 +556,7 @@ private: bool m_walking_parent; // are we building the parent map? UINT64 m_total_in; // total bytes in UINT64 m_total_out; // total bytes out - sha1_creator m_compsha1; // running SHA-1 on raw data + util::sha1_creator m_compsha1; // running SHA-1 on raw data // hash lookup maps hashmap m_parent_map; // hash map for parent diff --git a/src/lib/util/hash.cpp b/src/lib/util/hash.cpp new file mode 100644 index 00000000000..6d7ac9319e3 --- /dev/null +++ b/src/lib/util/hash.cpp @@ -0,0 +1,423 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + hash.cpp + + Function to handle hash functions (checksums) + + Based on original idea by Farfetch'd + +***************************************************************************/ + +#include "hash.h" +#include "hashing.h" +#include <ctype.h> + + +namespace util { +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +const char hash_collection::HASH_CRC; +const char hash_collection::HASH_SHA1; + +const char *hash_collection::HASH_TYPES_CRC = "R"; +const char *hash_collection::HASH_TYPES_CRC_SHA1 = "RS"; +const char *hash_collection::HASH_TYPES_ALL = "RS"; + +const char hash_collection::FLAG_NO_DUMP; +const char hash_collection::FLAG_BAD_DUMP; + + + +//************************************************************************** +// HASH COLLECTION +//************************************************************************** + +//------------------------------------------------- +// hash_collection - constructor +//------------------------------------------------- + +hash_collection::hash_collection() + : m_has_crc32(false), + m_has_sha1(false), + m_creator(nullptr) +{ +} + + +hash_collection::hash_collection(const char *string) + : m_has_crc32(false), + m_has_sha1(false), + m_creator(nullptr) +{ + from_internal_string(string); +} + + +hash_collection::hash_collection(const hash_collection &src) + : m_has_crc32(false), + m_has_sha1(false), + m_creator(nullptr) +{ + copyfrom(src); +} + + +//------------------------------------------------- +// ~hash_collection - destructor +//------------------------------------------------- + +hash_collection::~hash_collection() +{ + delete m_creator; +} + + +//------------------------------------------------- +// operator= - assignment operator +//------------------------------------------------- + +hash_collection &hash_collection::operator=(const hash_collection &src) +{ + // ignore self-assignment + if (this != &src) + copyfrom(src); + return *this; +} + + +//------------------------------------------------- +// operator== - test for equality +//------------------------------------------------- + +bool hash_collection::operator==(const hash_collection &rhs) const +{ + // match CRCs + int matches = 0; + if (m_has_crc32 && rhs.m_has_crc32) + { + if (m_crc32 != rhs.m_crc32) + return false; + matches++; + } + + // match SHA1s + if (m_has_sha1 && rhs.m_has_sha1) + { + if (m_sha1 != rhs.m_sha1) + return false; + matches++; + } + + // if all shared hashes match, return true + return (matches > 0); +} + + +//------------------------------------------------- +// hash_types - return a list of hash types as +// a string +//------------------------------------------------- + +std::string hash_collection::hash_types() const +{ + std::string buffer; + if (m_has_crc32) + buffer.push_back(HASH_CRC); + if (m_has_sha1) + buffer.push_back(HASH_SHA1); + return buffer; +} + + +//------------------------------------------------- +// reset - reset the hash collection to an empty +// set of hashes and flags +//------------------------------------------------- + +void hash_collection::reset() +{ + m_flags.clear(); + m_has_crc32 = m_has_sha1 = false; + delete m_creator; + m_creator = nullptr; +} + + +//------------------------------------------------- +// add_from_string - add a new hash, importing +// from a string +//------------------------------------------------- + +bool hash_collection::add_from_string(char type, const char *buffer, int length) +{ + // handle CRCs + if (type == HASH_CRC) + return m_has_crc32 = m_crc32.from_string(buffer, length); + + // handle SHA1s + else if (type == HASH_SHA1) + return m_has_sha1 = m_sha1.from_string(buffer, length); + + return false; +} + + +//------------------------------------------------- +// remove - remove a hash of the given type +//------------------------------------------------- + +bool hash_collection::remove(char type) +{ + bool result = false; + + // handle CRCs + if (type == HASH_CRC) + { + result = m_has_crc32; + m_has_crc32 = false; + } + + // handle SHA1s + else if (type == HASH_SHA1) + { + result = m_has_sha1; + m_has_sha1 = false; + } + return result; +} + + +//------------------------------------------------- +// internal_string - convert set of hashes and +// flags to a string in our internal compact +// format +//------------------------------------------------- + +std::string hash_collection::internal_string() const +{ + std::string buffer; + + // handle CRCs + if (m_has_crc32) { + buffer.push_back(HASH_CRC); + buffer.append(m_crc32.as_string()); + } + // handle SHA1s + if (m_has_sha1) { + buffer.push_back(HASH_SHA1); + buffer.append(m_sha1.as_string()); + } + + // append flags + buffer.append(m_flags); + return buffer; +} + + +//------------------------------------------------- +// macro_string - convert set of hashes and +// flags to a string in the macroized format +//------------------------------------------------- + +std::string hash_collection::macro_string() const +{ + std::string buffer; + + // handle CRCs + if (m_has_crc32) + buffer.append("CRC(").append(m_crc32.as_string()).append(") "); + + // handle SHA1s + if (m_has_sha1) + buffer.append("SHA1(").append(m_sha1.as_string()).append(") "); + + // append flags + if (flag(FLAG_NO_DUMP)) + buffer.append("NO_DUMP "); + if (flag(FLAG_BAD_DUMP)) + buffer.append("BAD_DUMP "); + strtrimspace(buffer); + return buffer; +} + + +//------------------------------------------------- +// attribute_string - convert set of hashes and +// flags to a string in XML attribute format +//------------------------------------------------- + +std::string hash_collection::attribute_string() const +{ + std::string buffer; + + // handle CRCs + if (m_has_crc32) + buffer.append("crc=\"").append(m_crc32.as_string()).append("\" "); + + // handle SHA1s + if (m_has_sha1) + buffer.append("sha1=\"").append(m_sha1.as_string()).append("\" "); + + // append flags + if (flag(FLAG_NO_DUMP)) + buffer.append("status=\"nodump\""); + if (flag(FLAG_BAD_DUMP)) + buffer.append("status=\"baddump\""); + strtrimspace(buffer); + return buffer; +} + + +//------------------------------------------------- +// from_internal_string - convert an internal +// compact string to set of hashes and flags +//------------------------------------------------- + +bool hash_collection::from_internal_string(const char *string) +{ + // start fresh + reset(); + + // determine the end of the string + const char *stringend = string + strlen(string); + const char *ptr = string; + + // loop until we hit it + bool errors = false; + int skip_digits = 0; + while (ptr < stringend) + { + char c = *ptr++; + char uc = toupper(c); + + // non-hex alpha values specify a hash type + if (uc >= 'G' && uc <= 'Z') + { + skip_digits = 0; + if (uc == HASH_CRC) + { + m_has_crc32 = true; + errors = !m_crc32.from_string(ptr, stringend - ptr); + skip_digits = 2 * sizeof(crc32_t); + } + else if (uc == HASH_SHA1) + { + m_has_sha1 = true; + errors = !m_sha1.from_string(ptr, stringend - ptr); + skip_digits = 2 * sizeof(sha1_t); + } + else + errors = true; + } + + // hex values are ignored, though unexpected + else if ((uc >= '0' && uc <= '9') || (uc >= 'A' && uc <= 'F')) + { + if (skip_digits != 0) + skip_digits--; + else + errors = true; + } + + // anything else is a flag + else if (skip_digits != 0) + errors = true; + else + m_flags.push_back(c); + } + return !errors; +} + + +//------------------------------------------------- +// begin - begin hashing +//------------------------------------------------- + +void hash_collection::begin(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; + + // 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); + } +} + + +//------------------------------------------------- +// buffer - add the given buffer to the hash +//------------------------------------------------- + +void hash_collection::buffer(const UINT8 *data, UINT32 length) +{ + assert(m_creator != nullptr); + + // 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 - stop hashing +//------------------------------------------------- + +void hash_collection::end() +{ + assert(m_creator != nullptr); + + // finish up the CRC32 + if (m_creator->m_doing_crc32) + { + m_has_crc32 = true; + m_crc32 = m_creator->m_crc32_creator.finish(); + } + + // finish up the SHA1 + if (m_creator->m_doing_sha1) + { + m_has_sha1 = true; + m_sha1 = m_creator->m_sha1_creator.finish(); + } + + // nuke the creator + delete m_creator; + m_creator = nullptr; +} + + +//------------------------------------------------- +// copyfrom - copy everything from another +// collection +//------------------------------------------------- + +void hash_collection::copyfrom(const hash_collection &src) +{ + // copy flags directly + m_flags = src.m_flags; + + // copy hashes + m_has_crc32 = src.m_has_crc32; + 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 diff --git a/src/lib/util/hash.h b/src/lib/util/hash.h new file mode 100644 index 00000000000..ec628a949f2 --- /dev/null +++ b/src/lib/util/hash.h @@ -0,0 +1,122 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + hash.h + + Function to handle hash functions (checksums) + + Based on original idea by Farfetch'd + +***************************************************************************/ + +#pragma once + +#ifndef __HASH_H__ +#define __HASH_H__ + +#include "hashing.h" + + +//************************************************************************** +// MACROS +//************************************************************************** + +// use these to define compile-time internal-format hash strings +#define CRC(x) "R" #x +#define SHA1(x) "S" #x +#define NO_DUMP "!" +#define BAD_DUMP "^" + + +namespace util { +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + + +// ======================> hash_collection + +// a collection of the various supported hashes and flags +class hash_collection +{ +public: + // hash types are identified by non-hex alpha values (G-Z) + static constexpr char HASH_CRC = 'R'; + static constexpr char HASH_SHA1 = 'S'; + + // common combinations for requests + static const char *HASH_TYPES_CRC; + static const char *HASH_TYPES_CRC_SHA1; + static const char *HASH_TYPES_ALL; + + // flags are identified by punctuation marks + static constexpr char FLAG_NO_DUMP = '!'; + static constexpr char FLAG_BAD_DUMP = '^'; + + // construction/destruction + hash_collection(); + hash_collection(const char *string); + hash_collection(const hash_collection &src); + ~hash_collection(); + + // operators + hash_collection &operator=(const hash_collection &src); + bool operator==(const hash_collection &rhs) const; + bool operator!=(const hash_collection &rhs) const { return !(*this == rhs); } + + // getters + bool flag(char flag) const { return (m_flags.find_first_of(flag) != std::string::npos); } + std::string hash_types() const; + + // hash manipulators + void reset(); + bool add_from_string(char type, const char *buffer, int length = -1); + bool remove(char type); + + // CRC-specific helpers + bool crc(UINT32 &result) const { result = m_crc32; return m_has_crc32; } + void add_crc(UINT32 crc) { m_crc32 = crc; m_has_crc32 = true; } + + // SHA1-specific helpers + bool sha1(sha1_t &result) const { result = m_sha1; return m_has_sha1; } + void add_sha1(sha1_t sha1) { m_has_sha1 = true; m_sha1 = sha1; } + + // string conversion + std::string internal_string() const; + std::string macro_string() const; + std::string attribute_string() const; + bool from_internal_string(const char *string); + + // creation + void begin(const char *types = nullptr); + void buffer(const UINT8 *data, UINT32 length); + void end(); + void compute(const UINT8 *data, UINT32 length, const char *types = nullptr) { begin(types); buffer(data, length); end(); } + +private: + // internal helpers + void copyfrom(const hash_collection &src); + + // internal state + std::string m_flags; + bool m_has_crc32; + crc32_t m_crc32; + bool m_has_sha1; + sha1_t m_sha1; + + // creators + struct hash_creator + { + bool m_doing_crc32; + crc32_creator m_crc32_creator; + bool m_doing_sha1; + sha1_creator m_sha1_creator; + }; + hash_creator * m_creator; +}; + + +} // namespace util + +#endif /* __HASH_H__ */ diff --git a/src/lib/util/hashing.cpp b/src/lib/util/hashing.cpp index 240e64af9ad..dd6b9847f15 100644 --- a/src/lib/util/hashing.cpp +++ b/src/lib/util/hashing.cpp @@ -14,6 +14,7 @@ #include <sstream> +namespace util { //************************************************************************** // CONSTANTS //************************************************************************** @@ -291,3 +292,5 @@ void crc16_creator::append(const void *data, UINT32 length) crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++]; m_accum.m_raw = crc; } + +} // namespace util diff --git a/src/lib/util/hashing.h b/src/lib/util/hashing.h index 51a7da7c694..8b58d3afc8b 100644 --- a/src/lib/util/hashing.h +++ b/src/lib/util/hashing.h @@ -20,6 +20,7 @@ #include "sha1.h" +namespace util { //************************************************************************** // TYPE DEFINITIONS //************************************************************************** @@ -217,4 +218,6 @@ protected: }; +} // namespace util + #endif // __HASHING_H__ |