diff --git a/cpp/src/monoformat_bithelpers.hpp b/cpp/src/monoformat_bithelpers.hpp new file mode 100644 index 0000000..d93fad6 --- /dev/null +++ b/cpp/src/monoformat_bithelpers.hpp @@ -0,0 +1,68 @@ +#ifndef MONOFORMAT_BITHELPERS_HPP +#define MONOFORMAT_BITHELPERS_HPP + +#include +#include +#include +#include + +namespace monoformat { + +template +constexpr inline bool isBitSet(Int value, OtherInt bit) { + if (bit < 0 || bit >= (sizeof(Int) * CHAR_BIT)) [[unlikely]] { + return false; + } + + Int mask = Int{1} << static_cast(bit); + return (value & mask) == mask; +} + +template +constexpr inline bool isBitSet(std::byte value, OtherInt bit) { + return isBitSet(static_cast(value), bit); +} + +template +constexpr inline void setBit(Int& value, OtherInt bit) { + if (bit < 0 || bit >= (sizeof(Int) * CHAR_BIT)) [[unlikely]] { + return; + } + + Int mask = Int{1} << static_cast(bit); + value |= mask; +} + +template +constexpr inline void setBit(std::byte& value, OtherInt bit) { + if (bit < 0 || bit >= CHAR_BIT) [[unlikely]] { + return; + } + + std::uint8_t mask = std::uint8_t{1} << static_cast(bit); + value = static_cast(static_cast(value) | mask); +} + +template +constexpr inline void unsetBit(Int& value, OtherInt bit) { + if (bit < 0 || bit >= (sizeof(Int) * CHAR_BIT)) [[unlikely]] { + return; + } + + Int mask = Int{1} << static_cast(bit); + value &= ~mask; +} + +template +constexpr inline void unsetBit(std::byte& value, OtherInt bit) { + if (bit < 0 || bit >= CHAR_BIT) [[unlikely]] { + return; + } + + std::uint8_t mask = std::uint8_t{1} << static_cast(bit); + value = static_cast(static_cast(value) & ~mask); +} + +} // namespace monoformat + +#endif // MONOFORMAT_BITHELPERS_HPP diff --git a/cpp/src/monoformat_parseonly.cpp b/cpp/src/monoformat_parseonly.cpp index 985d705..56398e1 100644 --- a/cpp/src/monoformat_parseonly.cpp +++ b/cpp/src/monoformat_parseonly.cpp @@ -1,6 +1,7 @@ #include "monoformat_parseonly.hpp" #include "monoformat_parsehelpers.hpp" #include "monoformat_fontreader.hpp" +#include "monoformat_bithelpers.hpp" #include #include @@ -58,10 +59,15 @@ static std::expected parseAlwaysDrawnSec data = data.subspan(*size - 8); AlwaysDrawnSectionMetaData result; - result.drawOnFront = (((*flags) >> 0u) & 0x01u) == 0x01u; - result.drawOnBack = (((*flags) >> 0u) & 0x02u) == 0x02u; - result.clearBeforeDrawing = (((*flags) >> 0u) & 0x04u) == 0x04u; + result.drawOnFront = isBitSet(*flags, 0); + result.drawOnBack = isBitSet(*flags, 1); + result.clearBeforeDrawing = isBitSet(*flags, 2); result.elementData = sectionData; + +#if defined(DEBUG) + std::cerr << "[Debug] AlwaysDrawnSection, drawOnFront = " << result.drawOnFront << ", drawOnBack = " << result.drawOnBack << ", clearBeforeDrawing = " << result.clearBeforeDrawing << ", element data size = " << result.elementData.size() << " bytes" << std::endl; +#endif + return result; } @@ -100,12 +106,17 @@ static std::expected parseTimeBasedDr data = data.subspan(*size - 24); TimeBasedDrawnSectionMetaData result; - result.base.drawOnFront = (((*flags) >> 0u) & 0x01u) == 0x01u; - result.base.drawOnBack = (((*flags) >> 0u) & 0x02u) == 0x02u; - result.base.clearBeforeDrawing = (((*flags) >> 0u) & 0x04u) == 0x04u; + result.base.drawOnFront = isBitSet(*flags, 0); + result.base.drawOnBack = isBitSet(*flags, 1); + result.base.clearBeforeDrawing = isBitSet(*flags, 2); result.base.elementData = sectionData; result.startTimestamp = std::bit_cast(*startTimestamp); result.endTimestamp = std::bit_cast(*endTimestamp); + +#if defined(DEBUG) + std::cerr << "[Debug] TimeBasedDrawnSection, drawOnFront = " << result.base.drawOnFront << ", drawOnBack = " << result.base.drawOnBack << ", clearBeforeDrawing = " << result.base.clearBeforeDrawing << ", element data size = " << result.base.elementData.size() << " bytes, timestamp between " << result.startTimestamp << " and " << result.endTimestamp << std::endl; +#endif + return result; } @@ -135,6 +146,10 @@ static std::expected, ParseError> parseCustomFontSect auto fontData = data.subspan(0, *size - 8); data = data.subspan(*size - 8); +#if defined(DEBUG) + std::cerr << "[Debug] CustomFontSection, font data size = " << *actualSize << " bytes" << std::endl; +#endif + return readBuffer(fontData, *actualSize); } @@ -292,6 +307,10 @@ std::expected handleImage(std::span& buffer, buffer = buffer.subspan(rounded - imageSize); } +#if defined(DEBUG) + std::cerr << "[Debug] - Image, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) << std::endl; +#endif + std::ignore = animationTick; std::ignore = currentTimestamp; std::ignore = customFonts; @@ -345,15 +364,22 @@ std::expected handleAnimation(std::span& buff return std::unexpected(reserved_.error()); } std::size_t imageSize = ((*width) * (*height) + 8 - 1) / 8; - auto imageData = readBuffer(buffer, imageSize); + auto imageData = readBuffer(buffer, imageSize * (*numberOfFrames)); if (!imageData) { return std::unexpected(reserved_.error()); } - std::size_t rounded = (imageSize + 4 - 1) / 4 * 4; - if (imageSize < rounded) { - buffer = buffer.subspan(rounded - imageSize); + std::size_t rounded = (imageSize * (*numberOfFrames) + 4 - 1) / 4 * 4; + if (imageSize * (*numberOfFrames) < rounded) { + buffer = buffer.subspan(rounded - imageSize * (*numberOfFrames)); } +#if defined(DEBUG) + std::cerr << "[Debug] - Animation, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) + << ", numberOfFrames = " << (*numberOfFrames) + << ", updateInterval = " << (*updateInterval) + << std::endl; +#endif + if (*numberOfFrames == 0) { return {}; } @@ -426,14 +452,22 @@ std::expected handleHScrollImage(std::span& b auto ownImage = ConstMemoryOneBitBuffer{*imageData, *contentWidth, *height}; ClippedImage target{screen, *x, *y, *width, *height}; +#if defined(DEBUG) + std::cerr << "[Debug] - HScrollImage, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) + << ", contentWidth = " << (*contentWidth) + << ", scrollSpeed = " << int(*scrollSpeed) + << ", flags = " << int(*flags) + << std::endl; +#endif + if (*contentWidth == 0) { return {}; } - bool restarting = ((*flags) & 0x01) == 0x00; - bool invert = ((*flags) & 0x02) == 0x02; - bool padBefore = ((*flags) & 0x04) == 0x04; - bool padAfter = ((*flags) & 0x08) == 0x08; + bool restarting = !isBitSet(*flags, 0); + bool invert = isBitSet(*flags, 1); + bool padBefore = isBitSet(*flags, 2); + bool padAfter = isBitSet(*flags, 3); if (!padBefore && !padAfter && *contentWidth < *width) { std::int16_t offset = invert ? (*width - *contentWidth) : 0; @@ -581,14 +615,22 @@ std::expected handleVScrollImage(std::span& b auto ownImage = ConstMemoryOneBitBuffer{*imageData, *width, *contentHeight}; ClippedImage target{screen, *x, *y, *width, *height}; +#if defined(DEBUG) + std::cerr << "[Debug] - VScrollImage, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) + << ", contentHeight = " << (*contentHeight) + << ", scrollSpeed = " << int(*scrollSpeed) + << ", flags = " << int(*flags) + << std::endl; +#endif + if (*contentHeight == 0) { return {}; } - bool restarting = ((*flags) & 0x01) == 0x00; - bool invert = ((*flags) & 0x02) == 0x02; - bool padBefore = ((*flags) & 0x04) == 0x04; - bool padAfter = ((*flags) & 0x08) == 0x08; + bool restarting = !isBitSet(*flags, 0); + bool invert = isBitSet(*flags, 1); + bool padBefore = isBitSet(*flags, 2); + bool padAfter = isBitSet(*flags, 3); if (!padBefore && !padAfter && *contentHeight < *height) { std::int16_t offset = invert ? (*height - *contentHeight) : 0; @@ -720,6 +762,12 @@ std::expected handleLine(std::span& buffer, O return std::unexpected(flags.error()); } +#if defined(DEBUG) + std::cerr << "[Debug] - Line, originX = " << (*originX) << ", originY = " << (*originY) << ", targetX = " << (*targetX) << ", targetY = " << (*targetY) + << ", lineStyle = " << int(*lineStyle) + << std::endl; +#endif + std::int32_t dx = static_cast(*targetX) - static_cast(*originX); std::int32_t dy = static_cast(*targetY) - static_cast(*originY); bool value = true; @@ -785,9 +833,16 @@ std::expected handleClippedText(std::span& bu } std::string_view text{reinterpret_cast(textData->data()), *textLength}; +#if defined(DEBUG) + std::cerr << "[Debug] - ClippedText, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) + << ", fontIndex = " << int(*fontIndex) + << ", text = \"" << text << "\"" + << std::endl; +#endif + std::span fontData; - if ((*fontIndex) & 0x8000u) { - fontIndex = (*fontIndex) & ~0x8000u; + if (isBitSet(*fontIndex, 15)) { + unsetBit(*fontIndex, 15); if (*fontIndex >= customFonts.size()) { return {}; } @@ -854,9 +909,18 @@ std::expected handleHScrollText(std::span& bu } std::string_view text{reinterpret_cast(textData->data()), *textLength}; +#if defined(DEBUG) + std::cerr << "[Debug] - HScrollText, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) + << ", scrollSpeed = " << int(*scrollSpeed) + << ", flags = " << int(*flags) + << ", fontIndex = " << int(*fontIndex) + << ", text = \"" << text << "\"" + << std::endl; +#endif + std::span fontData; - if ((*fontIndex) & 0x8000u) { - fontIndex = (*fontIndex) & ~0x8000u; + if (isBitSet(*fontIndex, 15)) { + unsetBit(*fontIndex, 15); if (*fontIndex >= customFonts.size()) { return {}; } @@ -880,10 +944,10 @@ std::expected handleHScrollText(std::span& bu return {}; } - bool restarting = ((*flags) & 0x01) == 0x00; - bool invert = ((*flags) & 0x02) == 0x02; - bool padBefore = ((*flags) & 0x04) == 0x04; - bool padAfter = ((*flags) & 0x08) == 0x08; + bool restarting = !isBitSet(*flags, 0); + bool invert = isBitSet(*flags, 1); + bool padBefore = isBitSet(*flags, 2); + bool padAfter = isBitSet(*flags, 3); if (!padBefore && !padAfter && contentWidth < *width) { std::uint16_t offset = invert ? (*width - contentWidth) : 0; @@ -994,9 +1058,17 @@ std::expected handleCurrentTime(std::span& bu return std::unexpected(flags.error()); } +#if defined(DEBUG) + std::cerr << "[Debug] - CurrentTime, x = " << (*x) << ", y = " << (*y) << ", width = " << (*width) << ", height = " << (*height) + << ", fontIndex = " << int(*fontIndex) + << ", utcOffset = " << int(*utcOffset) + << ", flags = " << int(*flags) + << std::endl; +#endif + std::span fontData; - if ((*fontIndex) & 0x8000u) { - fontIndex = (*fontIndex) & ~0x8000u; + if (isBitSet(*fontIndex, 15)) { + unsetBit(*fontIndex, 15); if (*fontIndex >= customFonts.size()) { return {}; } @@ -1009,10 +1081,10 @@ std::expected handleCurrentTime(std::span& bu } ClippedImage target{screen, *x, *y, *width, *height}; - bool use12h = ((*flags) & 0x01u) == 0x01u; - bool showHours = ((*flags) & 0x02u) == 0x02u; - bool showMinutes = ((*flags) & 0x04u) == 0x04u; - bool showSeconds = ((*flags) & 0x08u) == 0x08u; + bool use12h = isBitSet(*flags, 0); + bool showHours = isBitSet(*flags, 1); + bool showMinutes = isBitSet(*flags, 2); + bool showSeconds = isBitSet(*flags, 3); if (showHours && showSeconds) { showMinutes = true; } diff --git a/cpp/src/monoformat_schema.cpp b/cpp/src/monoformat_schema.cpp index d1f6f42..a469cf7 100644 --- a/cpp/src/monoformat_schema.cpp +++ b/cpp/src/monoformat_schema.cpp @@ -1,4 +1,5 @@ #include "monoformat_schema.hpp" +#include "monoformat_bithelpers.hpp" #include @@ -26,7 +27,7 @@ bool MemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const { std::size_t pxIndex = static_cast(y) * m_width + x; std::size_t byteIndex = pxIndex / 8; std::size_t bitIndex = pxIndex % 8; - return ((static_cast(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01; + return isBitSet(m_buffer[byteIndex], bitIndex); } void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) { @@ -37,9 +38,9 @@ void MemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) std::size_t byteIndex = pxIndex / 8; std::size_t bitIndex = pxIndex % 8; if (value) { - m_buffer[byteIndex] = static_cast(static_cast(m_buffer[byteIndex]) | (1u << bitIndex)); + setBit(m_buffer[byteIndex], bitIndex); } else { - m_buffer[byteIndex] = static_cast(static_cast(m_buffer[byteIndex]) & ~(1u << bitIndex)); + unsetBit(m_buffer[byteIndex], bitIndex); } } @@ -65,7 +66,7 @@ bool ConstMemoryOneBitBuffer::isPixelSet(std::uint16_t x, std::uint16_t y) const std::size_t pxIndex = static_cast(y) * m_width + x; std::size_t byteIndex = pxIndex / 8; std::size_t bitIndex = pxIndex % 8; - return ((static_cast(m_buffer[byteIndex]) >> bitIndex) & 0x01) == 0x01; + return isBitSet(m_buffer[byteIndex], bitIndex); } void ConstMemoryOneBitBuffer::setPixel(std::uint16_t x, std::uint16_t y, bool value) {