diff --git a/src/LibBGCode/binarize/binarize.cpp b/src/LibBGCode/binarize/binarize.cpp index 79bef19..adf4096 100644 --- a/src/LibBGCode/binarize/binarize.cpp +++ b/src/LibBGCode/binarize/binarize.cpp @@ -11,22 +11,28 @@ extern "C" { #include namespace bgcode { + using namespace core; + namespace binarize { -static bool write_to_file(FILE& file, const void* data, size_t data_size) +template +static bool write_to_file(FILE& file, const T* data, size_t data_size) { - const size_t wsize = fwrite(data, 1, data_size, &file); + const size_t wsize = fwrite(static_cast(data), 1, data_size, &file); return !ferror(&file) && wsize == data_size; } -static bool read_from_file(FILE& file, void* data, size_t data_size) +template +static bool read_from_file(FILE& file, T *data, size_t data_size) { - const size_t rsize = fread(data, 1, data_size, &file); + static_assert(!std::is_const_v, "Type of output buffer cannot be const!"); + + const size_t rsize = fread(static_cast(data), 1, data_size, &file); return !ferror(&file) && rsize == data_size; } -static std::vector encode(const void* data, size_t data_size) +static std::vector encode(const std::byte* data, size_t data_size) { std::vector ret(data_size); memcpy(ret.data(), data, data_size); @@ -135,7 +141,7 @@ static bool decode_gcode(const std::vector& src, std::string& dst, EGCo return true; } -static bool compress(const std::vector& src, std::vector& dst, ECompressionType compression_type) +static bool compress(std::vector& src, std::vector& dst, ECompressionType compression_type) { switch (compression_type) { @@ -147,8 +153,8 @@ static bool compress(const std::vector& src, std::vector& dst, std::vector temp_buffer(BUFSIZE); z_stream strm{}; - strm.next_in = const_cast(src.data()); - strm.avail_in = (uInt)src.size(); + strm.next_in = static_cast(src.data()); + strm.avail_in = static_cast(src.size()); strm.next_out = temp_buffer.data(); strm.avail_out = BUFSIZE; @@ -203,7 +209,7 @@ static bool compress(const std::vector& src, std::vector& dst, const size_t max_compressed_size = src_size + (src_size >> 2); dst.resize(max_compressed_size); - uint8_t* buf = const_cast(src.data()); + uint8_t* buf = src.data(); uint8_t* outbuf = dst.data(); // compress data @@ -403,10 +409,10 @@ EResult BaseMetadataBlock::write(FILE& file, EBlockType block_type, ECompression return res; // write block payload - if (!write_to_file(file, (const void*)&encoding_type, sizeof(encoding_type))) + if (!write_to_file(file, &encoding_type, sizeof(encoding_type))) return EResult::WriteError; if (!out_data.empty()) { - if (!write_to_file(file, (const void*)out_data.data(), out_data.size())) + if (!write_to_file(file, out_data.data(), out_data.size())) return EResult::WriteError; } @@ -416,7 +422,7 @@ EResult BaseMetadataBlock::write(FILE& file, EBlockType block_type, ECompression // update checksum with block payload checksum.append(encoding_type); if (!out_data.empty()) - checksum.append(out_data); + checksum.append(static_cast(out_data.data()), out_data.size()); } return EResult::Success; } @@ -573,7 +579,7 @@ EResult ThumbnailBlock::write(FILE& file, EChecksumType checksum_type) return EResult::InvalidThumbnailDataSize; // write block header - const BlockHeader block_header((uint16_t)EBlockType::Thumbnail, (uint16_t)ECompressionType::None, (uint32_t)data.size()); + BlockHeader block_header((uint16_t)EBlockType::Thumbnail, (uint16_t)ECompressionType::None, (uint32_t)data.size()); EResult res = block_header.write(file); if (res != EResult::Success) // propagate error @@ -585,7 +591,7 @@ EResult ThumbnailBlock::write(FILE& file, EChecksumType checksum_type) return res; } - if (!write_to_file(file, (const void*)data.data(), data.size())) + if (!write_to_file(file, data.data(), data.size())) return EResult::WriteError; if (checksum_type != EChecksumType::None) { @@ -673,10 +679,10 @@ EResult GCodeBlock::write(FILE& file, ECompressionType compression_type, EChecks return res; // write block payload - if (!write_to_file(file, (const void*)&encoding_type, sizeof(encoding_type))) + if (!write_to_file(file, &encoding_type, sizeof(encoding_type))) return EResult::WriteError; if (!out_data.empty()) { - if (!write_to_file(file, (const void*)out_data.data(), out_data.size())) + if (!write_to_file(file, out_data.data(), out_data.size())) return EResult::WriteError; } @@ -686,9 +692,11 @@ EResult GCodeBlock::write(FILE& file, ECompressionType compression_type, EChecks // update checksum with block header block_header.update_checksum(cs); // update checksum with block payload - cs.append(encode((const void*)&encoding_type, sizeof(encoding_type))); + std::vector data_to_encode = + encode(reinterpret_cast(&encoding_type), sizeof(encoding_type)); + cs.append(data_to_encode.data(), data_to_encode.size()); if (!out_data.empty()) - cs.append(out_data); + cs.append(static_cast(out_data.data()), out_data.size()); res = cs.write(file); if (res != EResult::Success) // propagate error diff --git a/src/LibBGCode/binarize/binarize.hpp b/src/LibBGCode/binarize/binarize.hpp index ab8dac5..45d76f3 100644 --- a/src/LibBGCode/binarize/binarize.hpp +++ b/src/LibBGCode/binarize/binarize.hpp @@ -1,12 +1,12 @@ -#ifndef _BGCODE_BINARIZE_HPP_ -#define _BGCODE_BINARIZE_HPP_ +#ifndef BGCODE_BINARIZE_HPP +#define BGCODE_BINARIZE_HPP #include "binarize/export.h" #include "core/core.hpp" namespace bgcode { namespace binarize { -struct BaseMetadataBlock +BGCODE_BINARIZE_EXPORT struct BaseMetadataBlock { // type of data encoding uint16_t encoding_type{ 0 }; @@ -19,7 +19,7 @@ struct BaseMetadataBlock core::EResult read_data(FILE& file, const core::BlockHeader& block_header); }; -struct FileMetadataBlock : public BaseMetadataBlock +BGCODE_BINARIZE_EXPORT struct FileMetadataBlock : public BaseMetadataBlock { // write block header and data core::EResult write(FILE& file, core::ECompressionType compression_type, core::EChecksumType checksum_type) const; @@ -27,7 +27,7 @@ struct FileMetadataBlock : public BaseMetadataBlock core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header); }; -struct PrintMetadataBlock : public BaseMetadataBlock +BGCODE_BINARIZE_EXPORT struct PrintMetadataBlock : public BaseMetadataBlock { // write block header and data core::EResult write(FILE& file, core::ECompressionType compression_type, core::EChecksumType checksum_type) const; @@ -35,7 +35,7 @@ struct PrintMetadataBlock : public BaseMetadataBlock core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header); }; -struct PrinterMetadataBlock : public BaseMetadataBlock +BGCODE_BINARIZE_EXPORT struct PrinterMetadataBlock : public BaseMetadataBlock { // write block header and data core::EResult write(FILE& file, core::ECompressionType compression_type, core::EChecksumType checksum_type) const; @@ -43,10 +43,10 @@ struct PrinterMetadataBlock : public BaseMetadataBlock core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header); }; -struct ThumbnailBlock +BGCODE_BINARIZE_EXPORT struct ThumbnailBlock { core::ThumbnailParams params; - std::vector data; + std::vector data; // write block header and data core::EResult write(FILE& file, core::EChecksumType checksum_type); @@ -57,7 +57,7 @@ struct ThumbnailBlock void update_checksum(core::Checksum& checksum) const; }; -struct GCodeBlock +BGCODE_BINARIZE_EXPORT struct GCodeBlock { uint16_t encoding_type{ 0 }; std::string raw_data; @@ -68,7 +68,7 @@ struct GCodeBlock core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header); }; -struct SlicerMetadataBlock : public BaseMetadataBlock +BGCODE_BINARIZE_EXPORT struct SlicerMetadataBlock : public BaseMetadataBlock { // write block header and data core::EResult write(FILE& file, core::ECompressionType compression_type, core::EChecksumType checksum_type) const; @@ -76,7 +76,7 @@ struct SlicerMetadataBlock : public BaseMetadataBlock core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header); }; -struct BinarizerConfig +BGCODE_BINARIZE_EXPORT struct BinarizerConfig { struct Compression { @@ -92,7 +92,7 @@ struct BinarizerConfig core::EChecksumType checksum{ core::EChecksumType::CRC32 }; }; -struct BinaryData +BGCODE_BINARIZE_EXPORT struct BinaryData { FileMetadataBlock file_metadata; PrinterMetadataBlock printer_metadata; @@ -101,7 +101,7 @@ struct BinaryData PrintMetadataBlock print_metadata; }; -class Binarizer +BGCODE_BINARIZE_EXPORT class Binarizer { public: bool is_enabled() const; @@ -128,4 +128,4 @@ class Binarizer }} // bgcode::core -#endif // _BGCODE_BINARIZE_HPP_ +#endif // BGCODE_BINARIZE_HPP_ diff --git a/src/LibBGCode/convert/convert.cpp b/src/LibBGCode/convert/convert.cpp index 112c71c..5a40a9e 100644 --- a/src/LibBGCode/convert/convert.cpp +++ b/src/LibBGCode/convert/convert.cpp @@ -453,11 +453,11 @@ BGCODE_CONVERT_EXPORT EResult from_ascii_to_binary(FILE& src_file, FILE& dst_fil ThumbnailBlock& thumbnail = binary_data.thumbnails.back(); if (thumbnail.data.size() > curr_thumbnail_data_loaded) thumbnail.data.resize(curr_thumbnail_data_loaded); - std::string decoded; - decoded.resize(boost::beast::detail::base64::decoded_size(thumbnail.data.size())); - decoded.resize(boost::beast::detail::base64::decode((void*)&decoded[0], (const char*)thumbnail.data.data(), thumbnail.data.size()).first); + std::vector decoded(boost::beast::detail::base64::decoded_size(thumbnail.data.size())); + auto thumbnail_buf = reinterpret_cast(thumbnail.data.data()); + decoded.resize(boost::beast::detail::base64::decode(decoded.data(), thumbnail_buf, thumbnail.data.size()).first); thumbnail.data.clear(); - thumbnail.data.insert(thumbnail.data.end(), decoded.begin(), decoded.end()); + std::copy(decoded.begin(), decoded.end(), std::back_inserter(thumbnail.data)); processed_lines.emplace_back(lines_counter++); return; } @@ -467,7 +467,8 @@ BGCODE_CONVERT_EXPORT EResult from_ascii_to_binary(FILE& src_file, FILE& dst_fil return; } ThumbnailBlock& thumbnail = binary_data.thumbnails.back(); - thumbnail.data.insert(thumbnail.data.begin() + curr_thumbnail_data_loaded, sv_line.begin(), sv_line.end()); + auto sv_line_bytes = reinterpret_cast(sv_line.data()); + thumbnail.data.insert(thumbnail.data.begin() + curr_thumbnail_data_loaded, sv_line_bytes, sv_line_bytes + sv_line.size()); curr_thumbnail_data_loaded += sv_line.size(); processed_lines.emplace_back(lines_counter++); return; @@ -561,7 +562,7 @@ BGCODE_CONVERT_EXPORT EResult from_ascii_to_binary(FILE& src_file, FILE& dst_fil BGCODE_CONVERT_EXPORT EResult from_binary_to_ascii(FILE& src_file, FILE& dst_file, bool verify_checksum) { // initialize buffer for checksum calculation, if verify_checksum is true - std::vector checksum_buffer; + std::vector checksum_buffer; if (verify_checksum) checksum_buffer.resize(65535); diff --git a/src/LibBGCode/core/core.cpp b/src/LibBGCode/core/core.cpp index 92033c0..5194b40 100644 --- a/src/LibBGCode/core/core.cpp +++ b/src/LibBGCode/core/core.cpp @@ -3,35 +3,24 @@ namespace bgcode { namespace core { -static bool write_to_file(FILE& file, const void* data, size_t data_size) +template +static bool write_to_file(FILE& file, const T* data, size_t data_size) { - const size_t wsize = fwrite(data, 1, data_size, &file); + const size_t wsize = fwrite(static_cast(data), 1, data_size, &file); return !ferror(&file) && wsize == data_size; } -static bool read_from_file(FILE& file, void* data, size_t data_size) +template +static bool read_from_file(FILE& file, T *data, size_t data_size) { - const size_t rsize = fread(data, 1, data_size, &file); - return !ferror(&file) && rsize == data_size; -} + static_assert(!std::is_const_v, "Type of output buffer cannot be const!"); -static uint32_t crc32_sw(const uint8_t* buffer, uint32_t length, uint32_t crc) -{ - uint32_t value = crc ^ 0xFFFFFFFF; - while (length--) { - value ^= (uint32_t)*buffer++; - for (int bit = 0; bit < 8; bit++) { - if (value & 1) - value = (value >> 1) ^ 0xEDB88320; - else - value >>= 1; - } - } - value ^= 0xFFFFFFFF; - return value; + const size_t rsize = fread(static_cast(data), 1, data_size, &file); + return !ferror(&file) && rsize == data_size; } -EResult verify_block_checksum(FILE& file, const FileHeader& file_header, const BlockHeader& block_header, uint8_t* buffer, size_t buffer_size) +EResult verify_block_checksum(FILE& file, const FileHeader& file_header, + const BlockHeader& block_header, std::byte* buffer, size_t buffer_size) { if (buffer == nullptr || buffer_size == 0) return EResult::InvalidBuffer; @@ -77,41 +66,18 @@ static uint16_t block_types_count() { return 1 + (uint16_t)EBlockType::Thu static uint16_t compression_types_count() { return 1 + (uint16_t)ECompressionType::Heatshrink_12_4; } Checksum::Checksum(EChecksumType type) -: m_type(type) + : m_type(type), m_size(checksum_size(type)) { - m_checksum.fill(0); - m_size = checksum_size(type); + m_checksum.fill(std::byte{0}); } EChecksumType Checksum::get_type() const { return m_type; } -void Checksum::append(const std::vector& data) +void Checksum::append(const std::vector& data) { append(data.data(), data.size()); } -void Checksum::append(const uint8_t* data, size_t size) -{ - if (data == nullptr || size == 0) - return; - - switch (m_type) - { - case EChecksumType::None: - { - break; - } - case EChecksumType::CRC32: - { - static_assert(sizeof(m_checksum) >= sizeof(uint32_t), "CRC32 checksum requires at least 4 bytes"); - const uint32_t old_crc = *(uint32_t*)m_checksum.data(); - const uint32_t new_crc = crc32_sw(data, (uint32_t)size, old_crc); - *(uint32_t*)m_checksum.data() = new_crc; - break; - } - } -} - bool Checksum::matches(Checksum& other) { return m_checksum == other.m_checksum; @@ -120,7 +86,7 @@ bool Checksum::matches(Checksum& other) EResult Checksum::write(FILE& file) { if (m_type != EChecksumType::None) { - if (!write_to_file(file, (const void*)m_checksum.data(), m_size)) + if (!write_to_file(file, m_checksum.data(), m_size)) return EResult::WriteError; } return EResult::Success; @@ -129,7 +95,7 @@ EResult Checksum::write(FILE& file) EResult Checksum::read(FILE& file) { if (m_type != EChecksumType::None) { - if (!read_from_file(file, (void*)m_checksum.data(), m_size)) + if (!read_from_file(file, m_checksum.data(), m_size)) return EResult::ReadError; } return EResult::Success; @@ -137,16 +103,16 @@ EResult Checksum::read(FILE& file) EResult FileHeader::write(FILE& file) const { - if (magic != *(uint32_t*)(MAGIC.data())) + if (magic != MAGICi32) return EResult::InvalidMagicNumber; if (checksum_type >= checksum_types_count()) return EResult::InvalidChecksumType; - if (!write_to_file(file, (const void*)&magic, sizeof(magic))) + if (!write_to_file(file, &magic, sizeof(magic))) return EResult::WriteError; - if (!write_to_file(file, (const void*)&version, sizeof(version))) + if (!write_to_file(file, &version, sizeof(version))) return EResult::WriteError; - if (!write_to_file(file, (const void*)&checksum_type, sizeof(checksum_type))) + if (!write_to_file(file, &checksum_type, sizeof(checksum_type))) return EResult::WriteError; return EResult::Success; @@ -154,17 +120,17 @@ EResult FileHeader::write(FILE& file) const EResult FileHeader::read(FILE& file, const uint32_t* const max_version) { - if (!read_from_file(file, (void*)&magic, sizeof(magic))) + if (!read_from_file(file, &magic, sizeof(magic))) return EResult::ReadError; - if (magic != *(uint32_t*)(MAGIC.data())) + if (magic != MAGICi32) return EResult::InvalidMagicNumber; - if (!read_from_file(file, (void*)&version, sizeof(version))) + if (!read_from_file(file, &version, sizeof(version))) return EResult::ReadError; if (max_version != nullptr && version > *max_version) return EResult::InvalidVersionNumber; - if (!read_from_file(file, (void*)&checksum_type, sizeof(checksum_type))) + if (!read_from_file(file, &checksum_type, sizeof(checksum_type))) return EResult::ReadError; if (checksum_type >= checksum_types_count()) return EResult::InvalidChecksumType; @@ -193,17 +159,17 @@ long BlockHeader::get_position() const return m_position; } -EResult BlockHeader::write(FILE& file) const +EResult BlockHeader::write(FILE& file) { m_position = ftell(&file); - if (!write_to_file(file, (const void*)&type, sizeof(type))) + if (!write_to_file(file, &type, sizeof(type))) return EResult::WriteError; - if (!write_to_file(file, (const void*)&compression, sizeof(compression))) + if (!write_to_file(file, &compression, sizeof(compression))) return EResult::WriteError; - if (!write_to_file(file, (const void*)&uncompressed_size, sizeof(uncompressed_size))) + if (!write_to_file(file, &uncompressed_size, sizeof(uncompressed_size))) return EResult::WriteError; if (compression != (uint16_t)ECompressionType::None) { - if (!write_to_file(file, (const void*)&compressed_size, sizeof(compressed_size))) + if (!write_to_file(file, &compressed_size, sizeof(compressed_size))) return EResult::WriteError; } return EResult::Success; @@ -212,20 +178,20 @@ EResult BlockHeader::write(FILE& file) const EResult BlockHeader::read(FILE& file) { m_position = ftell(&file); - if (!read_from_file(file, (void*)&type, sizeof(type))) + if (!read_from_file(file, &type, sizeof(type))) return EResult::ReadError; if (type >= block_types_count()) return EResult::InvalidBlockType; - if (!read_from_file(file, (void*)&compression, sizeof(compression))) + if (!read_from_file(file, &compression, sizeof(compression))) return EResult::ReadError; if (compression >= compression_types_count()) return EResult::InvalidCompressionType; - if (!read_from_file(file, (void*)&uncompressed_size, sizeof(uncompressed_size))) + if (!read_from_file(file, &uncompressed_size, sizeof(uncompressed_size))) return EResult::ReadError; if (compression != (uint16_t)ECompressionType::None) { - if (!read_from_file(file, (void*)&compressed_size, sizeof(compressed_size))) + if (!read_from_file(file, &compressed_size, sizeof(compressed_size))) return EResult::ReadError; } @@ -238,21 +204,21 @@ size_t BlockHeader::get_size() const { } EResult ThumbnailParams::write(FILE& file) const { - if (!write_to_file(file, (const void*)&format, sizeof(format))) + if (!write_to_file(file, &format, sizeof(format))) return EResult::WriteError; - if (!write_to_file(file, (const void*)&width, sizeof(width))) + if (!write_to_file(file, &width, sizeof(width))) return EResult::WriteError; - if (!write_to_file(file, (const void*)&height, sizeof(height))) + if (!write_to_file(file, &height, sizeof(height))) return EResult::WriteError; return EResult::Success; } EResult ThumbnailParams::read(FILE& file){ - if (!read_from_file(file, (void*)&format, sizeof(format))) + if (!read_from_file(file, &format, sizeof(format))) return EResult::ReadError; - if (!read_from_file(file, (void*)&width, sizeof(width))) + if (!read_from_file(file, &width, sizeof(width))) return EResult::ReadError; - if (!read_from_file(file, (void*)&height, sizeof(height))) + if (!read_from_file(file, &height, sizeof(height))) return EResult::ReadError; return EResult::Success; } @@ -296,14 +262,14 @@ BGCODE_CORE_EXPORT std::string_view translate_result(EResult result) return std::string_view(); } -BGCODE_CORE_EXPORT EResult is_valid_binary_gcode(FILE& file, bool check_contents, uint8_t* cs_buffer, size_t cs_buffer_size) +BGCODE_CORE_EXPORT EResult is_valid_binary_gcode(FILE& file, bool check_contents, std::byte* cs_buffer, size_t cs_buffer_size) { // cache file position const long curr_pos = ftell(&file); rewind(&file); // check magic number - std::array magic; + std::array magic; const size_t rsize = fread((void*)magic.data(), 1, magic.size(), &file); if (ferror(&file) && rsize != magic.size()) return EResult::ReadError; @@ -464,13 +430,13 @@ BGCODE_CORE_EXPORT EResult read_header(FILE& file, FileHeader& header, const uin } BGCODE_CORE_EXPORT EResult read_next_block_header(FILE& file, const FileHeader& file_header, BlockHeader& block_header, - uint8_t* cs_buffer, size_t cs_buffer_size) + std::byte* cs_buffer, size_t cs_buffer_size) { EResult res = block_header.read(file); if (res == EResult::Success && cs_buffer != nullptr && cs_buffer_size > 0) { res = verify_block_checksum(file, file_header, block_header, cs_buffer, cs_buffer_size); // return to payload position after checksum verification - if (fseek(&file, block_header.get_position() + (long)block_header.get_size(), SEEK_SET) != 0) + if (fseek(&file, block_header.get_position() + static_cast(block_header.get_size()), SEEK_SET) != 0) res = EResult::ReadError; } @@ -478,7 +444,7 @@ BGCODE_CORE_EXPORT EResult read_next_block_header(FILE& file, const FileHeader& } BGCODE_CORE_EXPORT EResult read_next_block_header(FILE& file, const FileHeader& file_header, BlockHeader& block_header, EBlockType type, - uint8_t* cs_buffer, size_t cs_buffer_size) + std::byte* cs_buffer, size_t cs_buffer_size) { // cache file position const long curr_pos = ftell(&file); diff --git a/src/LibBGCode/core/core.hpp b/src/LibBGCode/core/core.hpp index 0a34aa6..17c9e65 100644 --- a/src/LibBGCode/core/core.hpp +++ b/src/LibBGCode/core/core.hpp @@ -5,6 +5,10 @@ #include #include +#include +#include +#include +#include #include #include #include @@ -12,13 +16,92 @@ namespace bgcode { namespace core { -static constexpr const std::array MAGIC{ 'G', 'C', 'D', 'E' }; +static constexpr const std::array MAGIC{ 'G', 'C', 'D', 'E' }; // Library version static constexpr const uint32_t VERSION = 1; // Max size of checksum buffer data, in bytes // Increase this value if you implement a checksum algorithm needing a bigger buffer static constexpr const size_t MAX_CHECKSUM_SIZE = 4; +template +using IntegerOnly = std::enable_if_t, T>; + +template +using remove_cvref_t = std::remove_cv_t>; + +template constexpr bool IsBufferType = + std::is_convertible_v, std::byte> || + std::is_convertible_v, unsigned char> || + std::is_convertible_v, char>; + +template constexpr bool IsBufferIterator = + IsBufferType< typename std::iterator_traits::value_type>; + +template +using BufferTypeOnly = std::enable_if_t, T>; + +template +using BufferIteratorOnly = std::enable_if_t, T>; + +// For LE byte sequences only +template> +constexpr IntegerOnly load_integer(It from, It to) noexcept +{ + IntT result{}; + + size_t i = 0; + for (It it = from; it != to && i < sizeof(IntT); ++it) { + result |= (static_cast(*it) << (i++ * sizeof(std::byte) * CHAR_BIT)); + } + + return result; +} + +template +constexpr BufferIteratorOnly +store_integer_le(IntT value, OutIt out, size_t sz = sizeof(IntT)) +{ + for (size_t i = 0; i < std::min(sizeof(IntT), sz); ++i) + { + *out++ = static_cast::value_type>( + (value >> (i * CHAR_BIT)) & UCHAR_MAX + ); + } +} + +template +std::enable_if_t, void> +store_integer_le(IntT value, OutIt out, size_t sz = sizeof(IntT)) +{ + for (size_t i = 0; i < std::min(sizeof(IntT), sz); ++i) + { + *out++ = (value >> (i * CHAR_BIT)) & UCHAR_MAX; + } +} + +template> +static constexpr uint32_t crc32_sw(It from, It to, uint32_t crc) +{ + constexpr uint32_t ui32Max = 0xFFFFFFFF; + constexpr uint32_t crcMagic = 0xEDB88320; + + uint32_t value = crc ^ ui32Max; + for (auto it = from; it != to; ++it) { + value ^= load_integer(it, std::next(it)); + for (int bit = 0; bit < CHAR_BIT; bit++) { + if (value & 1) + value = (value >> 1) ^ crcMagic; + else + value >>= 1; + } + } + value ^= ui32Max; + + return value; +} + +constexpr auto MAGICi32 = load_integer(std::begin(MAGIC), std::end(MAGIC)); + enum class EResult : uint16_t { Success, @@ -96,7 +179,7 @@ enum class EThumbnailFormat : uint16_t QOI }; -class Checksum +BGCODE_CORE_EXPORT class Checksum { public: // Constructs a checksum of the given type. @@ -106,12 +189,35 @@ class Checksum EChecksumType get_type() const; // Append vector of data to checksum - void append(const std::vector& data); + void append(const std::vector& data); + // Append data to the checksum - void append(const uint8_t* data, size_t size); + template + void append(const BufT* data, size_t size) + { + if (data == nullptr || size == 0) + return; + + switch (m_type) + { + case EChecksumType::None: + { + break; + } + case EChecksumType::CRC32: + { + static_assert(sizeof(m_checksum) >= sizeof(uint32_t), "CRC32 checksum requires at least 4 bytes"); + const auto old_crc = load_integer(m_checksum.begin(), m_checksum.end()); //*(uint32_t*)m_checksum.data(); + const uint32_t new_crc = crc32_sw(data, data + size, old_crc); + store_integer_le(new_crc, m_checksum.begin(), m_checksum.size()); + break; + } + } + } + // Append any aritmetic data to the checksum (shorthand for aritmetic types) template::value, T>::type> - void append(T& data) { append(reinterpret_cast(&data), sizeof(data)); } + void append(T& data) { append(reinterpret_cast(&data), sizeof(data)); } // Returns true if the given checksum is equal to this one bool matches(Checksum& other); @@ -123,12 +229,12 @@ class Checksum EChecksumType m_type; // actual size of checksum buffer, type dependent size_t m_size; - std::array m_checksum; + std::array m_checksum; }; -struct FileHeader +BGCODE_CORE_EXPORT struct FileHeader { - uint32_t magic{ *(uint32_t*)(MAGIC.data()) }; + uint32_t magic{ MAGICi32 }; uint32_t version{ VERSION }; uint16_t checksum_type{ static_cast(EChecksumType::None) }; @@ -136,7 +242,7 @@ struct FileHeader EResult read(FILE& file, const uint32_t* const max_version); }; -struct BlockHeader +BGCODE_CORE_EXPORT struct BlockHeader { uint16_t type{ 0 }; uint16_t compression{ 0 }; @@ -153,17 +259,17 @@ struct BlockHeader // Position is set by calling write() and read() methods. long get_position() const; - EResult write(FILE& file) const; + EResult write(FILE& file); EResult read(FILE& file); // Returs the size of this BlockHeader, in bytes size_t get_size() const; private: - mutable long m_position{ 0 }; + long m_position{ 0 }; }; -struct ThumbnailParams +BGCODE_CORE_EXPORT struct ThumbnailParams { uint16_t format; uint16_t width; @@ -180,7 +286,7 @@ extern BGCODE_CORE_EXPORT std::string_view translate_result(EResult result); // If check_contents is set to true, the order of the blocks is checked // Does not modify the file position // Caller is responsible for providing buffer for checksum calculation, if needed. -extern BGCODE_CORE_EXPORT EResult is_valid_binary_gcode(FILE& file, bool check_contents = false, uint8_t* cs_buffer = nullptr, +extern BGCODE_CORE_EXPORT EResult is_valid_binary_gcode(FILE& file, bool check_contents = false, std::byte* cs_buffer = nullptr, size_t cs_buffer_size = 0); // Reads the file header. @@ -197,7 +303,7 @@ extern BGCODE_CORE_EXPORT EResult read_header(FILE& file, FileHeader& header, co // - file position will be set at the start of the block parameters data. // Caller is responsible for providing buffer for checksum calculation, if needed. extern BGCODE_CORE_EXPORT EResult read_next_block_header(FILE& file, const FileHeader& file_header, BlockHeader& block_header, - uint8_t* cs_buffer = nullptr, size_t cs_buffer_size = 0); + std::byte* cs_buffer = nullptr, size_t cs_buffer_size = 0); // Searches and reads next block header with the given type from the current file position. // File position must be at the start of a block header. @@ -208,13 +314,13 @@ extern BGCODE_CORE_EXPORT EResult read_next_block_header(FILE& file, const FileH // - file position will keep the current value. // Caller is responsible for providing buffer for checksum calculation, if needed. extern BGCODE_CORE_EXPORT EResult read_next_block_header(FILE& file, const FileHeader& file_header, BlockHeader& block_header, EBlockType type, - uint8_t* cs_buffer = nullptr, size_t cs_buffer_size = 0); + std::byte* cs_buffer = nullptr, size_t cs_buffer_size = 0); // Calculates block checksum and verify it against checksum stored in file. // Caller is responsible for providing buffer for checksum calculation, bigger buffer means faster calculation and vice versa. // If return == EResult::Success: // - file position will be set at the start of the next block header. -extern BGCODE_CORE_EXPORT EResult verify_block_checksum(FILE& file, const FileHeader& file_header, const BlockHeader& block_header, uint8_t* buffer, +extern BGCODE_CORE_EXPORT EResult verify_block_checksum(FILE& file, const FileHeader& file_header, const BlockHeader& block_header, std::byte* buffer, size_t buffer_size); // Skips the content (parameters + data + checksum) of the block with the given block header. diff --git a/src/LibBGCode/python/pybgcode.cpp b/src/LibBGCode/python/pybgcode.cpp index c16ba2c..1fd5163 100644 --- a/src/LibBGCode/python/pybgcode.cpp +++ b/src/LibBGCode/python/pybgcode.cpp @@ -166,7 +166,9 @@ PYBIND11_MODULE(pybgcode, m) { py::class_(m, "Checksum") .def(py::init()) .def("get_type", &core::Checksum::get_type) - .def("append", static_cast &)> (&core::Checksum::append)) + .def("append", [](core::Checksum &self, const std::string &buf) { + self.append(buf.data(), buf.size()); + }) .def("matches", &core::Checksum::matches) .def("read", [](core::Checksum &self, FILEWrapper &file) { return self.read(*file.fptr); @@ -223,7 +225,7 @@ PYBIND11_MODULE(pybgcode, m) { m.def( "is_valid_binary_gcode", [](FILEWrapper& file, bool check_contents) { - std::vector cs_buffer; + std::vector cs_buffer; if (check_contents) cs_buffer.resize(MaxBuffSz); @@ -296,7 +298,7 @@ PYBIND11_MODULE(pybgcode, m) { m.def( "verify_block_checksum", [](FILEWrapper& file, const core::FileHeader& file_header, const core::BlockHeader& block_header){ - std::array buff; + std::array buff; return core::verify_block_checksum(*file.fptr, file_header, block_header, buff.data(), buff.size()); }, R"pbdoc( diff --git a/tests/core/core_tests.cpp b/tests/core/core_tests.cpp index bf00210..2445395 100644 --- a/tests/core/core_tests.cpp +++ b/tests/core/core_tests.cpp @@ -89,7 +89,7 @@ static std::string thumbnail_format_as_string(EThumbnailFormat type) std::cout << "File:" << filename << "\n"; const size_t MAX_CHECKSUM_CACHE_SIZE = 2048; - uint8_t checksum_verify_buffer[MAX_CHECKSUM_CACHE_SIZE]; + std::byte checksum_verify_buffer[MAX_CHECKSUM_CACHE_SIZE]; FILE* file = boost::nowide::fopen(filename.c_str(), "rb"); REQUIRE(file != nullptr); @@ -166,7 +166,7 @@ static std::string thumbnail_format_as_string(EThumbnailFormat type) std::cout << "File:" << filename << "\n"; const size_t MAX_CHECKSUM_CACHE_SIZE = 2048; - uint8_t checksum_verify_buffer[MAX_CHECKSUM_CACHE_SIZE]; + std::byte checksum_verify_buffer[MAX_CHECKSUM_CACHE_SIZE]; FILE* file = boost::nowide::fopen(filename.c_str(), "rb"); REQUIRE(file != nullptr);