Compare commits

...

2 Commits

Author SHA1 Message Date
Christian Seiler 51f60eb817 C++/Structured: implement serialization functions 4 weeks ago
Christian Seiler 328f338a6c Fix bug in specification (text length missing) 4 weeks ago
  1. 2
      Specification.rst
  2. 120
      cpp/src/monoformat_parsehelpers.hpp
  3. 178
      cpp/src/monoformat_structured.cpp

@ -379,7 +379,7 @@ Horizontally Scrolling Text
+------------------------+------------------------+------------------------+------------------------+ +------------------------+------------------------+------------------------+------------------------+
8 | Height | Flags | Scroll Speed | 8 | Height | Flags | Scroll Speed |
+------------------------+------------------------+------------------------+------------------------+ +------------------------+------------------------+------------------------+------------------------+
12 | Font Index | Text ... | 12 | Font Index | Text Length |
+------------------------+------------------------+------------------------+------------------------+ +------------------------+------------------------+------------------------+------------------------+
... | ... Text | Padding (if required) | ... | ... Text | Padding (if required) |
+------------------------+------------------------+------------------------+------------------------+ +------------------------+------------------------+------------------------+------------------------+

@ -5,6 +5,7 @@
#include <cstddef> #include <cstddef>
#include <expected> #include <expected>
#include <span> #include <span>
#include <tuple> // for std::ignore
namespace monoformat { namespace monoformat {
@ -228,6 +229,125 @@ inline std::pair<std::uint8_t, bool> overflowingShl(std::uint8_t value, std::uin
return {value << bits, overflow}; return {value << bits, overflow};
} }
inline std::size_t writeU8LE(std::span<std::byte>& target, std::size_t pos, std::uint8_t value) {
if (pos < target.size()) {
target[pos] = static_cast<std::byte>(value);
}
return pos + 1;
}
inline std::size_t writeU8BE(std::span<std::byte>& target, std::size_t pos, std::uint8_t value) {
if (pos < target.size()) {
target[pos] = static_cast<std::byte>(value);
}
return pos + 1;
}
inline std::size_t writeU16LE(std::span<std::byte>& target, std::size_t pos, std::uint16_t value) {
if ((pos + 1) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
}
return pos + 2;
}
inline std::size_t writeU16BE(std::span<std::byte>& target, std::size_t pos, std::uint16_t value) {
if ((pos + 1) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 0u) & 0xffu);
}
return pos + 2;
}
inline std::size_t writeU24LE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
if ((pos + 2) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 2] = static_cast<std::byte>((value >> 16u) & 0xffu);
}
return pos + 3;
}
inline std::size_t writeU24BE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
if ((pos + 2) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 16u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 2] = static_cast<std::byte>((value >> 0u) & 0xffu);
}
return pos + 3;
}
inline std::size_t writeU32LE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
if ((pos + 3) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 2] = static_cast<std::byte>((value >> 16u) & 0xffu);
target[pos + 3] = static_cast<std::byte>((value >> 24u) & 0xffu);
}
return pos + 4;
}
inline std::size_t writeU32BE(std::span<std::byte>& target, std::size_t pos, std::uint32_t value) {
if ((pos + 3) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 24u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 16u) & 0xffu);
target[pos + 2] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 3] = static_cast<std::byte>((value >> 0u) & 0xffu);
}
return pos + 4;
}
inline std::size_t writeU64LE(std::span<std::byte>& target, std::size_t pos, std::uint64_t value) {
if ((pos + 7) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 0u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 2] = static_cast<std::byte>((value >> 16u) & 0xffu);
target[pos + 3] = static_cast<std::byte>((value >> 24u) & 0xffu);
target[pos + 4] = static_cast<std::byte>((value >> 32u) & 0xffu);
target[pos + 5] = static_cast<std::byte>((value >> 40u) & 0xffu);
target[pos + 6] = static_cast<std::byte>((value >> 48u) & 0xffu);
target[pos + 7] = static_cast<std::byte>((value >> 56u) & 0xffu);
}
return pos + 8;
}
inline std::size_t writeU64BE(std::span<std::byte>& target, std::size_t pos, std::uint64_t value) {
if ((pos + 3) < target.size()) {
target[pos + 0] = static_cast<std::byte>((value >> 56u) & 0xffu);
target[pos + 1] = static_cast<std::byte>((value >> 48u) & 0xffu);
target[pos + 2] = static_cast<std::byte>((value >> 40u) & 0xffu);
target[pos + 3] = static_cast<std::byte>((value >> 32u) & 0xffu);
target[pos + 4] = static_cast<std::byte>((value >> 24u) & 0xffu);
target[pos + 5] = static_cast<std::byte>((value >> 16u) & 0xffu);
target[pos + 6] = static_cast<std::byte>((value >> 8u) & 0xffu);
target[pos + 7] = static_cast<std::byte>((value >> 0u) & 0xffu);
}
return pos + 8;
}
inline std::size_t writeBuffer(std::span<std::byte>& target, std::size_t pos, std::span<std::byte const> value) {
if ((pos + value.size()) > target.size()) {
if (pos < value.size()) {
std::size_t const n = value.size() - pos;
std::copy(value.begin(), value.begin() + n, target.begin() + pos);
}
} else {
std::copy(value.begin(), value.end(), target.begin() + pos);
}
return pos + value.size();
}
inline std::size_t alignNextWrite(std::span<std::byte>& target, std::size_t pos, std::size_t alignment) {
std::ignore = target;
if (alignment <= 1) {
return pos;
}
if (pos % alignment == 0) {
return pos;
}
return ((pos + alignment - 1) / alignment) * alignment;
}
} // namespace monoformat } // namespace monoformat
#endif // MONOFORMAT_PARSEHELPERS_HPP #endif // MONOFORMAT_PARSEHELPERS_HPP

@ -122,7 +122,15 @@ ElementType ImageElement::elementType() const {
} }
std::size_t ImageElement::serializeTo(std::span<std::byte> target) const { std::size_t ImageElement::serializeTo(std::span<std::byte> target) const {
// FIXME: serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::Image));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU16LE(target, pos, 0);
pos = writeBuffer(target, pos, m_buffer);
return alignNextWrite(target, pos, 4);
} }
void ImageElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void ImageElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -209,7 +217,17 @@ ElementType AnimationElement::elementType() const {
} }
std::size_t AnimationElement::serializeTo(std::span<std::byte> target) const { std::size_t AnimationElement::serializeTo(std::span<std::byte> target) const {
// FIXME: implement this std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::Animation));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU16LE(target, pos, m_numberOfFrames);
pos = writeU16LE(target, pos, m_updateInterval);
pos = writeU16LE(target, pos, 0);
pos = writeBuffer(target, pos, m_buffer);
return alignNextWrite(target, pos, 4);
} }
void AnimationElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void AnimationElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -285,7 +303,18 @@ ElementType HScrollImageElement::elementType() const {
} }
std::size_t HScrollImageElement::serializeTo(std::span<std::byte> target) const { std::size_t HScrollImageElement::serializeTo(std::span<std::byte> target) const {
// FIXME Serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU16LE(target, pos, m_contentWidth);
pos = writeU8LE(target, pos, m_flags);
pos = writeU8LE(target, pos, m_scrollSpeed);
pos = writeU16LE(target, pos, 0);
pos = writeBuffer(target, pos, m_buffer);
return alignNextWrite(target, pos, 4);
} }
void HScrollImageElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void HScrollImageElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -361,7 +390,18 @@ ElementType VScrollImageElement::elementType() const {
} }
std::size_t VScrollImageElement::serializeTo(std::span<std::byte> target) const { std::size_t VScrollImageElement::serializeTo(std::span<std::byte> target) const {
// FIXME Serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::VScrollImage));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU16LE(target, pos, m_contentHeight);
pos = writeU8LE(target, pos, m_flags);
pos = writeU8LE(target, pos, m_scrollSpeed);
pos = writeU16LE(target, pos, 0);
pos = writeBuffer(target, pos, m_buffer);
return alignNextWrite(target, pos, 4);
} }
void VScrollImageElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void VScrollImageElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -415,7 +455,15 @@ ElementType LineElement::elementType() const {
} }
std::size_t LineElement::serializeTo(std::span<std::byte> target) const { std::size_t LineElement::serializeTo(std::span<std::byte> target) const {
// FIXME: serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::Line));
pos = writeU16LE(target, pos, m_originX);
pos = writeU16LE(target, pos, m_originY);
pos = writeU16LE(target, pos, m_targetX);
pos = writeU16LE(target, pos, m_targetY);
pos = writeU8LE(target, pos, static_cast<std::uint8_t>(m_lineStyle));
pos = writeU8LE(target, pos, m_flags);
return alignNextWrite(target, pos, 4);
} }
void LineElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void LineElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -468,7 +516,16 @@ ElementType ClippedTextElement::elementType() const {
} }
std::size_t ClippedTextElement::serializeTo(std::span<std::byte> target) const { std::size_t ClippedTextElement::serializeTo(std::span<std::byte> target) const {
// FIXME: serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU16LE(target, pos, m_fontIndex);
pos = writeU16LE(target, pos, m_text.size());
pos = writeBuffer(target, pos, std::as_bytes(std::span{m_text}));
return alignNextWrite(target, pos, 4);
} }
void ClippedTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void ClippedTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -531,7 +588,18 @@ ElementType HScrollTextElement::elementType() const {
} }
std::size_t HScrollTextElement::serializeTo(std::span<std::byte> target) const { std::size_t HScrollTextElement::serializeTo(std::span<std::byte> target) const {
// FIXME serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU8LE(target, pos, m_flags);
pos = writeU8LE(target, pos, m_scrollSpeed);
pos = writeU16LE(target, pos, m_fontIndex);
pos = writeU16LE(target, pos, m_text.size());
pos = writeBuffer(target, pos, std::as_bytes(std::span{m_text}));
return alignNextWrite(target, pos, 4);
} }
void HScrollTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void HScrollTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -589,7 +657,16 @@ ElementType CurrentTimeElement::elementType() const {
} }
std::size_t CurrentTimeElement::serializeTo(std::span<std::byte> target) const { std::size_t CurrentTimeElement::serializeTo(std::span<std::byte> target) const {
// FIXME: serialize std::size_t pos = 0;
pos = writeU16LE(target, pos, static_cast<std::uint16_t>(ElementType::HScrollImage));
pos = writeU16LE(target, pos, m_x);
pos = writeU16LE(target, pos, m_y);
pos = writeU16LE(target, pos, m_width);
pos = writeU16LE(target, pos, m_height);
pos = writeU16LE(target, pos, m_fontIndex);
pos = writeU16LE(target, pos, m_utcOffset);
pos = writeU16LE(target, pos, m_flags);
return alignNextWrite(target, pos, 4);
} }
void CurrentTimeElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) { void CurrentTimeElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t animationTick, std::int64_t currentTimestamp) {
@ -674,7 +751,32 @@ SectionType AlwaysDrawnSection::sectionType() const {
} }
std::size_t AlwaysDrawnSection::serializeTo(std::span<std::byte> target) const { std::size_t AlwaysDrawnSection::serializeTo(std::span<std::byte> target) const {
// FIXME: serialize std::size_t pos = 0;
pos = writeU8LE(target, pos, static_cast<std::uint16_t>(SectionType::AlwaysDrawn));
// Will be replaced later
pos = writeU24LE(target, pos, 0);
std::uint16_t flags = 0;
if (m_drawOnFront) {
flags |= std::uint16_t{1};
}
if (m_drawOnBack) {
flags |= std::uint16_t{2};
}
if (m_clearBeforeDrawing) {
flags |= std::uint16_t{4};
}
pos = writeU16LE(target, pos, flags);
pos = writeU16LE(target, pos, m_elements.size());
for (auto const& element : m_elements) {
if (pos < target.size()) {
pos += element->serializeTo(target.subspan(pos));
} else {
pos += element->serializeTo({});
}
}
pos = alignNextWrite(target, pos, 4);
std::ignore = writeU24LE(target, 1, pos);
return pos;
} }
std::expected<std::unique_ptr<AlwaysDrawnSection>, ParseError> AlwaysDrawnSection::parse(std::span<std::byte const>& buffer) { std::expected<std::unique_ptr<AlwaysDrawnSection>, ParseError> AlwaysDrawnSection::parse(std::span<std::byte const>& buffer) {
@ -771,7 +873,34 @@ SectionType TimeBasedDrawnSection::sectionType() const {
} }
std::size_t TimeBasedDrawnSection::serializeTo(std::span<std::byte> target) const { std::size_t TimeBasedDrawnSection::serializeTo(std::span<std::byte> target) const {
// FIXME: serialize std::size_t pos = 0;
pos = writeU8LE(target, pos, static_cast<std::uint16_t>(SectionType::AlwaysDrawn));
// Will be replaced later
pos = writeU24LE(target, pos, 0);
std::uint16_t flags = 0;
if (m_drawOnFront) {
flags |= std::uint16_t{1};
}
if (m_drawOnBack) {
flags |= std::uint16_t{2};
}
if (m_clearBeforeDrawing) {
flags |= std::uint16_t{4};
}
pos = writeU16LE(target, pos, flags);
pos = writeU16LE(target, pos, m_elements.size());
pos = writeU64LE(target, pos, std::bit_cast<std::uint64_t>(m_startTimestamp));
pos = writeU64LE(target, pos, std::bit_cast<std::uint64_t>(m_endTimestamp));
for (auto const& element : m_elements) {
if (pos < target.size()) {
pos += element->serializeTo(target.subspan(pos));
} else {
pos += element->serializeTo({});
}
}
pos = alignNextWrite(target, pos, 4);
std::ignore = writeU24LE(target, 1, pos);
return pos;
} }
std::expected<std::unique_ptr<TimeBasedDrawnSection>, ParseError> TimeBasedDrawnSection::parse(std::span<std::byte const>& buffer) { std::expected<std::unique_ptr<TimeBasedDrawnSection>, ParseError> TimeBasedDrawnSection::parse(std::span<std::byte const>& buffer) {
@ -795,7 +924,16 @@ SectionType CustomFontSection::sectionType() const {
} }
std::size_t CustomFontSection::serializeTo(std::span<std::byte> target) const { std::size_t CustomFontSection::serializeTo(std::span<std::byte> target) const {
// FIXME: serailize std::size_t pos = 0;
pos = writeU8LE(target, pos, static_cast<std::uint16_t>(SectionType::AlwaysDrawn));
// Will be replaced later
pos = writeU24LE(target, pos, 0);
pos = writeU24LE(target, pos, m_fontData.size());
pos = writeU8LE(target, pos, 0);
pos = writeBuffer(target, pos, m_fontData);
pos = alignNextWrite(target, pos, 4);
std::ignore = writeU24LE(target, 1, pos);
return pos;
} }
std::expected<std::unique_ptr<CustomFontSection>, ParseError> CustomFontSection::parse(std::span<std::byte const>& buffer) { std::expected<std::unique_ptr<CustomFontSection>, ParseError> CustomFontSection::parse(std::span<std::byte const>& buffer) {
@ -803,7 +941,23 @@ std::expected<std::unique_ptr<CustomFontSection>, ParseError> CustomFontSection:
} }
std::size_t serializeFile(std::span<std::byte>& buffer, File const& file) { std::size_t serializeFile(std::span<std::byte>& buffer, File const& file) {
// FIXME: serialize std::size_t pos = 0;
pos = writeU8LE(buffer, pos, 0xAF);
pos = writeU8LE(buffer, pos, 0x7E);
pos = writeU8LE(buffer, pos, 0x2B);
pos = writeU8LE(buffer, pos, 0x64);
pos = writeU32LE(buffer, pos, 1);
pos = writeU16LE(buffer, pos, file.sections.size());
pos = writeU16LE(buffer, pos, 0);
pos = alignNextWrite(buffer, pos, 4);
for (auto const& section : file.sections) {
if (pos < buffer.size()) {
pos += section->serializeTo(buffer.subspan(pos));
} else {
pos += section->serializeTo({});
}
}
return pos;
} }
std::expected<File, ParseError> parseFile(std::span<std::byte const> data) { std::expected<File, ParseError> parseFile(std::span<std::byte const> data) {

Loading…
Cancel
Save