@ -3,9 +3,51 @@
# include "monoformat_bithelpers.hpp"
# include "monoformat_bithelpers.hpp"
# include <iostream>
# include <iostream>
# include <stdexcept>
# include <format>
namespace monoformat {
namespace monoformat {
static std : : string base64Encode ( std : : span < std : : byte const > buffer ) ;
static std : : vector < std : : byte > base64Decode ( std : : string_view data ) ;
NLOHMANN_JSON_SERIALIZE_ENUM ( SectionType , {
{ SectionType : : AlwaysDrawn , " AlwaysDrawn " } ,
{ SectionType : : TimeBasedDrawn , " TimeBasedDrawn " } ,
{ SectionType : : CustomFont , " CustomFont " } ,
} )
NLOHMANN_JSON_SERIALIZE_ENUM ( ElementType , {
{ ElementType : : Image , " Image " } ,
{ ElementType : : Animation , " Animation " } ,
{ ElementType : : HScrollImage , " HScrollImage " } ,
{ ElementType : : VScrollImage , " VScrollImage " } ,
{ ElementType : : Line , " Line " } ,
{ ElementType : : ClippedText , " ClippedText " } ,
{ ElementType : : HScrollText , " HScrollText " } ,
{ ElementType : : CurrentTime , " CurrentTime " } ,
} )
NLOHMANN_JSON_SERIALIZE_ENUM ( LineStyle , {
{ LineStyle : : Solid , " Solid " } ,
} )
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT ( ScrollFlags , endless , invertDirection , padBefore , padAfter )
// Don't use NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT here because our struct is empty
static void from_json ( nlohmann : : json const & j , LineFlags & v ) {
if ( ! j . is_object ( ) | | j . size ( ) > 0 ) {
throw std : : runtime_error ( " Cannot deserialize a LineFlags that is not an empty object " ) ;
}
v = { } ;
}
static void to_json ( nlohmann : : json & j , LineFlags const & v ) {
std : : ignore = v ;
j = nlohmann : : json : : object ( ) ;
}
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT ( TimeDisplayFlags , use12h , showHours , showMinutes , showSeconds )
ImageElement : : ImageElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height )
ImageElement : : ImageElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -66,6 +108,8 @@ std::uint32_t ImageElement::minimumFormatVersion() const {
}
}
std : : size_t ImageElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t ImageElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : Image ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : Image ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -77,6 +121,27 @@ std::size_t ImageElement::serializeTo(std::span<std::byte> target, std::uint32_t
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json ImageElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " Image " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " image " ] = nlohmann : : json : : array ( ) ;
auto ownImage = image ( ) ;
for ( std : : uint16_t dy = 0 ; dy < m_height ; + + dy ) {
for ( std : : uint16_t dx = 0 ; dx < m_width ; + + dx ) {
result [ " image " ] . push_back ( ownImage . isPixelSet ( dx , dy ) ? 1 : 0 ) ;
}
}
return result ;
}
void ImageElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void ImageElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = animationTick ;
std : : ignore = animationTick ;
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
@ -134,6 +199,28 @@ std::expected<std::unique_ptr<ImageElement>, ParseError> ImageElement::parse(std
return result ;
return result ;
}
}
std : : unique_ptr < ImageElement > ImageElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
std : : vector < int > pixels = j . at ( " image " ) ;
if ( pixels . size ( ) ! = width * height ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an Image element: the width, {:d}, and height {:d}, of the image don't match the number of pixels in the image data, {:d}, expected {:d} instead " , width , height , pixels . size ( ) , width * height ) ) ;
}
auto result = std : : make_unique < ImageElement > ( x , y , width , height ) ;
auto image = result - > image ( ) ;
for ( std : : uint16_t dy = 0 ; dy < height ; + + dy ) {
std : : size_t base = static_cast < std : : size_t > ( dy ) * width ;
for ( std : : uint16_t dx = 0 ; dx < width ; + + dx ) {
image . setPixel ( dx , dy , ! ! pixels [ base + dx ] ) ;
}
}
return result ;
}
AnimationElement : : AnimationElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t numberOfFrames , std : : uint16_t updateInterval )
AnimationElement : : AnimationElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t numberOfFrames , std : : uint16_t updateInterval )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -220,6 +307,8 @@ std::uint32_t AnimationElement::minimumFormatVersion() const {
}
}
std : : size_t AnimationElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t AnimationElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : Animation ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : Animation ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -233,6 +322,32 @@ std::size_t AnimationElement::serializeTo(std::span<std::byte> target, std::uint
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json AnimationElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " Animation " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " updateInterval " ] = m_updateInterval ;
result [ " frames " ] = nlohmann : : json : : array ( ) ;
for ( std : : uint16_t f = 0 ; f < m_numberOfFrames ; + + f ) {
nlohmann : : json frame = nlohmann : : json : : array ( ) ;
auto ownImage = image ( f ) ;
for ( std : : uint16_t dy = 0 ; dy < m_height ; + + dy ) {
for ( std : : uint16_t dx = 0 ; dx < m_width ; + + dx ) {
frame . push_back ( ownImage . isPixelSet ( dx , dy ) ? 1 : 0 ) ;
}
}
result [ " frames " ] . push_back ( frame ) ;
}
return result ;
}
void AnimationElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void AnimationElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
std : : ignore = customFonts ;
std : : ignore = customFonts ;
@ -305,6 +420,38 @@ std::expected<std::unique_ptr<AnimationElement>, ParseError> AnimationElement::p
return result ;
return result ;
}
}
std : : unique_ptr < AnimationElement > AnimationElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
std : : uint16_t updateInterval = j . at ( " updateInterval " ) ;
std : : vector < std : : vector < int > > frames = j . at ( " frames " ) ;
if ( frames . size ( ) > std : : numeric_limits < std : : uint16_t > : : max ( ) ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an Animation element: the number of frames, {:d}, is too large " , frames . size ( ) ) ) ;
}
for ( std : : size_t i = 0 ; i < frames . size ( ) ; + + i ) {
if ( frames [ i ] . size ( ) ! = width * height ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an Animation element: in frame {:d}, the width, {:d}, and height {:d}, of the image don't match the number of pixels in the image data, {:d}, expected {:d} instead " , i , width , height , frames [ i ] . size ( ) , width * height ) ) ;
}
}
auto result = std : : make_unique < AnimationElement > ( x , y , width , height , static_cast < std : : uint16_t > ( frames . size ( ) ) , updateInterval ) ;
for ( std : : size_t i = 0 ; i < frames . size ( ) ; + + i ) {
auto image = result - > image ( i ) ;
for ( std : : uint16_t dy = 0 ; dy < height ; + + dy ) {
std : : size_t base = static_cast < std : : size_t > ( dy ) * width ;
for ( std : : uint16_t dx = 0 ; dx < width ; + + dx ) {
image . setPixel ( dx , dy , ! ! frames [ i ] [ base + dx ] ) ;
}
}
}
return result ;
}
HScrollImageElement : : HScrollImageElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t contentWidth , ScrollFlags flags , std : : uint8_t scrollSpeed )
HScrollImageElement : : HScrollImageElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t contentWidth , ScrollFlags flags , std : : uint8_t scrollSpeed )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -380,6 +527,8 @@ std::uint32_t HScrollImageElement::minimumFormatVersion() const {
}
}
std : : size_t HScrollImageElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t HScrollImageElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : HScrollImage ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : HScrollImage ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -394,6 +543,30 @@ std::size_t HScrollImageElement::serializeTo(std::span<std::byte> target, std::u
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json HScrollImageElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " HScrollImage " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " contentWidth " ] = m_contentWidth ;
result [ " flags " ] = m_flags ;
result [ " scrollSpeed " ] = int ( m_scrollSpeed ) ;
result [ " image " ] = nlohmann : : json : : array ( ) ;
auto ownImage = image ( ) ;
for ( std : : uint16_t dy = 0 ; dy < m_height ; + + dy ) {
for ( std : : uint16_t dx = 0 ; dx < m_contentWidth ; + + dx ) {
result [ " image " ] . push_back ( ownImage . isPixelSet ( dx , dy ) ? 1 : 0 ) ;
}
}
return result ;
}
void HScrollImageElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void HScrollImageElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
std : : ignore = customFonts ;
std : : ignore = customFonts ;
@ -555,6 +728,35 @@ std::expected<std::unique_ptr<HScrollImageElement>, ParseError> HScrollImageElem
return result ;
return result ;
}
}
std : : unique_ptr < HScrollImageElement > HScrollImageElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
std : : uint16_t contentWidth = j . at ( " contentWidth " ) ;
ScrollFlags flags = j . at ( " flags " ) ;
int scrollSpeed = j . at ( " scrollSpeed " ) ;
std : : vector < int > pixels = j . at ( " image " ) ;
if ( scrollSpeed < 0 | | scrollSpeed > 255 ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an HScrollImage element: invalid scroll speed {:d} specified " , scrollSpeed ) ) ;
}
if ( pixels . size ( ) ! = contentWidth * height ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an HScrollImage element: the content width, {:d}, and height {:d}, of the image don't match the number of pixels in the image data, {:d}, expected {:d} instead " , contentWidth , height , pixels . size ( ) , contentWidth * height ) ) ;
}
auto result = std : : make_unique < HScrollImageElement > ( x , y , width , height , contentWidth , flags , static_cast < std : : uint8_t > ( scrollSpeed ) ) ;
auto image = result - > image ( ) ;
for ( std : : uint16_t dy = 0 ; dy < height ; + + dy ) {
std : : size_t base = static_cast < std : : size_t > ( dy ) * contentWidth ;
for ( std : : uint16_t dx = 0 ; dx < contentWidth ; + + dx ) {
image . setPixel ( dx , dy , ! ! pixels [ base + dx ] ) ;
}
}
return result ;
}
VScrollImageElement : : VScrollImageElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t contentHeight , ScrollFlags flags , std : : uint8_t scrollSpeed )
VScrollImageElement : : VScrollImageElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t contentHeight , ScrollFlags flags , std : : uint8_t scrollSpeed )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -630,6 +832,8 @@ std::uint32_t VScrollImageElement::minimumFormatVersion() const {
}
}
std : : size_t VScrollImageElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t VScrollImageElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : VScrollImage ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : VScrollImage ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -644,6 +848,30 @@ std::size_t VScrollImageElement::serializeTo(std::span<std::byte> target, std::u
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json VScrollImageElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " VScrollImage " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " contentHeight " ] = m_contentHeight ;
result [ " flags " ] = m_flags ;
result [ " scrollSpeed " ] = int ( m_scrollSpeed ) ;
result [ " image " ] = nlohmann : : json : : array ( ) ;
auto ownImage = image ( ) ;
for ( std : : uint16_t dy = 0 ; dy < m_contentHeight ; + + dy ) {
for ( std : : uint16_t dx = 0 ; dx < m_width ; + + dx ) {
result [ " image " ] . push_back ( ownImage . isPixelSet ( dx , dy ) ? 1 : 0 ) ;
}
}
return result ;
}
void VScrollImageElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void VScrollImageElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
std : : ignore = customFonts ;
std : : ignore = customFonts ;
@ -805,6 +1033,34 @@ std::expected<std::unique_ptr<VScrollImageElement>, ParseError> VScrollImageElem
return result ;
return result ;
}
}
std : : unique_ptr < VScrollImageElement > VScrollImageElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
std : : uint16_t contentHeight = j . at ( " contentHeight " ) ;
ScrollFlags flags = j . at ( " flags " ) ;
int scrollSpeed = j . at ( " scrollSpeed " ) ;
std : : vector < int > pixels = j . at ( " image " ) ;
if ( scrollSpeed < 0 | | scrollSpeed > 255 ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an VScrollImage element: invalid scroll speed {:d} specified " , scrollSpeed ) ) ;
}
if ( pixels . size ( ) ! = width * contentHeight ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an VScrollImage element: the width, {:d}, and content height {:d}, of the image don't match the number of pixels in the image data, {:d}, expected {:d} instead " , width , contentHeight , pixels . size ( ) , width * contentHeight ) ) ;
}
auto result = std : : make_unique < VScrollImageElement > ( x , y , width , height , contentHeight , flags , static_cast < std : : uint8_t > ( scrollSpeed ) ) ;
auto image = result - > image ( ) ;
for ( std : : uint16_t dy = 0 ; dy < contentHeight ; + + dy ) {
std : : size_t base = static_cast < std : : size_t > ( dy ) * width ;
for ( std : : uint16_t dx = 0 ; dx < width ; + + dx ) {
image . setPixel ( dx , dy , ! ! pixels [ base + dx ] ) ;
}
}
return result ;
}
LineElement : : LineElement ( std : : uint16_t originX , std : : uint16_t originY , std : : uint16_t targetX , std : : uint16_t targetY , LineStyle lineStyle , LineFlags flags )
LineElement : : LineElement ( std : : uint16_t originX , std : : uint16_t originY , std : : uint16_t targetX , std : : uint16_t targetY , LineStyle lineStyle , LineFlags flags )
: m_originX { originX }
: m_originX { originX }
@ -852,6 +1108,8 @@ std::uint32_t LineElement::minimumFormatVersion() const {
}
}
std : : size_t LineElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t LineElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : Line ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : Line ) ) ;
pos = writeU16LE ( target , pos , m_originX ) ;
pos = writeU16LE ( target , pos , m_originX ) ;
@ -863,6 +1121,20 @@ std::size_t LineElement::serializeTo(std::span<std::byte> target, std::uint32_t
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json LineElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " Line " ;
result [ " originX " ] = m_originX ;
result [ " originY " ] = m_originY ;
result [ " targetX " ] = m_targetX ;
result [ " targetY " ] = m_targetY ;
result [ " lineStyle " ] = m_lineStyle ;
result [ " flags " ] = m_flags ;
return result ;
}
void LineElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void LineElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = animationTick ;
std : : ignore = animationTick ;
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
@ -930,6 +1202,20 @@ std::expected<std::unique_ptr<LineElement>, ParseError> LineElement::parse(std::
return result ;
return result ;
}
}
std : : unique_ptr < LineElement > LineElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t originX = j . at ( " originX " ) ;
std : : uint16_t originY = j . at ( " originY " ) ;
std : : uint16_t targetX = j . at ( " targetX " ) ;
std : : uint16_t targetY = j . at ( " targetY " ) ;
LineStyle lineStyle = j . at ( " lineStyle " ) ;
LineFlags flags = j . at ( " flags " ) ;
auto result = std : : make_unique < LineElement > ( originX , originY , targetX , targetY , lineStyle , flags ) ;
return result ;
}
ClippedTextElement : : ClippedTextElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t fontIndex , std : : string text )
ClippedTextElement : : ClippedTextElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t fontIndex , std : : string text )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -976,6 +1262,8 @@ std::uint32_t ClippedTextElement::minimumFormatVersion() const {
}
}
std : : size_t ClippedTextElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t ClippedTextElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : ClippedText ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : ClippedText ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -988,6 +1276,20 @@ std::size_t ClippedTextElement::serializeTo(std::span<std::byte> target, std::ui
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json ClippedTextElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " ClippedText " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " fontIndex " ] = m_fontIndex ;
result [ " text " ] = m_text ;
return result ;
}
void ClippedTextElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void ClippedTextElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = animationTick ;
std : : ignore = animationTick ;
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
@ -1056,6 +1358,20 @@ std::expected<std::unique_ptr<ClippedTextElement>, ParseError> ClippedTextElemen
return result ;
return result ;
}
}
std : : unique_ptr < ClippedTextElement > ClippedTextElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
std : : uint16_t fontIndex = j . at ( " fontIndex " ) ;
std : : string text = j . at ( " text " ) ;
auto result = std : : make_unique < ClippedTextElement > ( x , y , width , height , fontIndex , std : : move ( text ) ) ;
return result ;
}
HScrollTextElement : : HScrollTextElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , ScrollFlags flags , std : : uint8_t scrollSpeed , std : : uint16_t fontIndex , std : : string text )
HScrollTextElement : : HScrollTextElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , ScrollFlags flags , std : : uint8_t scrollSpeed , std : : uint16_t fontIndex , std : : string text )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -1112,6 +1428,8 @@ std::uint32_t HScrollTextElement::minimumFormatVersion() const {
}
}
std : : size_t HScrollTextElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t HScrollTextElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : HScrollText ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : HScrollText ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -1126,6 +1444,22 @@ std::size_t HScrollTextElement::serializeTo(std::span<std::byte> target, std::ui
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json HScrollTextElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " HScrollText " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " flags " ] = m_flags ;
result [ " scrollSpeed " ] = int ( m_scrollSpeed ) ;
result [ " fontIndex " ] = m_fontIndex ;
result [ " text " ] = m_text ;
return result ;
}
void HScrollTextElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void HScrollTextElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = currentTimestamp ;
std : : ignore = currentTimestamp ;
@ -1282,6 +1616,27 @@ std::expected<std::unique_ptr<HScrollTextElement>, ParseError> HScrollTextElemen
return result ;
return result ;
}
}
std : : unique_ptr < HScrollTextElement > HScrollTextElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
ScrollFlags flags = j . at ( " flags " ) ;
int scrollSpeed = j . at ( " scrollSpeed " ) ;
std : : uint16_t fontIndex = j . at ( " fontIndex " ) ;
std : : string text = j . at ( " text " ) ;
if ( scrollSpeed < 0 | | scrollSpeed > 255 ) {
throw std : : runtime_error ( std : : format ( " Error unserializing an HScrollText element: invalid scroll speed {:d} specified " , scrollSpeed ) ) ;
}
auto result = std : : make_unique < HScrollTextElement > ( x , y , width , height , flags , static_cast < std : : uint8_t > ( scrollSpeed ) , fontIndex , std : : move ( text ) ) ;
return result ;
}
CurrentTimeElement : : CurrentTimeElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t fontIndex , std : : uint16_t utcOffset , TimeDisplayFlags flags )
CurrentTimeElement : : CurrentTimeElement ( std : : uint16_t x , std : : uint16_t y , std : : uint16_t width , std : : uint16_t height , std : : uint16_t fontIndex , std : : uint16_t utcOffset , TimeDisplayFlags flags )
: m_x { x }
: m_x { x }
, m_y { y }
, m_y { y }
@ -1333,6 +1688,8 @@ std::uint32_t CurrentTimeElement::minimumFormatVersion() const {
}
}
std : : size_t CurrentTimeElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t CurrentTimeElement : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : CurrentTime ) ) ;
pos = writeU16LE ( target , pos , static_cast < std : : uint16_t > ( ElementType : : CurrentTime ) ) ;
pos = writeU16LE ( target , pos , m_x ) ;
pos = writeU16LE ( target , pos , m_x ) ;
@ -1345,6 +1702,21 @@ std::size_t CurrentTimeElement::serializeTo(std::span<std::byte> target, std::ui
return alignNextWrite ( target , pos , 4 ) ;
return alignNextWrite ( target , pos , 4 ) ;
}
}
nlohmann : : json CurrentTimeElement : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " CurrentTime " ;
result [ " x " ] = m_x ;
result [ " y " ] = m_y ;
result [ " width " ] = m_width ;
result [ " height " ] = m_height ;
result [ " fontIndex " ] = m_fontIndex ;
result [ " utcOffset " ] = m_utcOffset ;
result [ " flags " ] = m_flags ;
return result ;
}
void CurrentTimeElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
void CurrentTimeElement : : drawTo ( OneBitBufferInterface * imageBuffer , std : : size_t animationTick , std : : int64_t currentTimestamp , std : : span < CustomFontSection const * > customFonts ) {
std : : ignore = animationTick ;
std : : ignore = animationTick ;
@ -1444,6 +1816,21 @@ std::expected<std::unique_ptr<CurrentTimeElement>, ParseError> CurrentTimeElemen
return result ;
return result ;
}
}
std : : unique_ptr < CurrentTimeElement > CurrentTimeElement : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : uint16_t x = j . at ( " x " ) ;
std : : uint16_t y = j . at ( " y " ) ;
std : : uint16_t width = j . at ( " width " ) ;
std : : uint16_t height = j . at ( " height " ) ;
std : : uint16_t fontIndex = j . at ( " fontIndex " ) ;
std : : uint16_t utcOffset = j . at ( " utcOffset " ) ;
TimeDisplayFlags flags = j . at ( " flags " ) ;
auto result = std : : make_unique < CurrentTimeElement > ( x , y , width , height , fontIndex , utcOffset , flags ) ;
return result ;
}
AlwaysDrawnSection : : ~ AlwaysDrawnSection ( ) {
AlwaysDrawnSection : : ~ AlwaysDrawnSection ( ) {
}
}
@ -1548,9 +1935,22 @@ std::size_t AlwaysDrawnSection::serializeTo(std::span<std::byte> target, std::ui
return pos ;
return pos ;
}
}
std : : expected < std : : unique_ptr < AlwaysDrawnSection > , ParseError > AlwaysDrawnSection : : parse ( std : : span < std : : byte const > & buffer , std : : uint32_t formatVersion ) {
nlohmann : : json AlwaysDrawnSection : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " AlwaysDrawn " ;
result [ " flags " ] [ " drawOnFront " ] = m_drawOnFront ;
result [ " flags " ] [ " drawOnBack " ] = m_drawOnBack ;
result [ " flags " ] [ " clearBeforeDrawing " ] = m_clearBeforeDrawing ;
result [ " elements " ] = nlohmann : : json : : array ( ) ;
for ( auto const & element : m_elements ) {
result [ " elements " ] . push_back ( element - > serializeJSON ( formatVersion ) ) ;
}
return result ;
}
std : : expected < std : : unique_ptr < AlwaysDrawnSection > , ParseError > AlwaysDrawnSection : : parse ( std : : span < std : : byte const > & buffer , std : : uint32_t formatVersion ) {
auto type = readU8LE ( buffer ) ;
auto type = readU8LE ( buffer ) ;
if ( ! type ) {
if ( ! type ) {
return std : : unexpected ( type . error ( ) ) ;
return std : : unexpected ( type . error ( ) ) ;
@ -1606,6 +2006,38 @@ std::expected<std::unique_ptr<AlwaysDrawnSection>, ParseError> AlwaysDrawnSectio
return section ;
return section ;
}
}
std : : unique_ptr < AlwaysDrawnSection > AlwaysDrawnSection : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
bool drawOnFront = j . at ( " flags " ) . at ( " drawOnFront " ) ;
bool drawOnBack = j . at ( " flags " ) . at ( " drawOnBack " ) ;
bool clearBeforeDrawing = j . at ( " flags " ) . at ( " clearBeforeDrawing " ) ;
auto section = std : : make_unique < AlwaysDrawnSection > ( ) ;
section - > setDrawOnFront ( drawOnFront ) ;
section - > setDrawOnBack ( drawOnBack ) ;
section - > setClearBeforeDrawing ( clearBeforeDrawing ) ;
std : : size_t const elementCount = j . at ( " elements " ) . size ( ) ;
for ( std : : size_t i = 0 ; i < elementCount ; + + i ) {
nlohmann : : json const & jElement = j . at ( " elements " ) . at ( i ) ;
ElementType type = jElement . at ( " type " ) ;
std : : unique_ptr < Element > element ;
switch ( type ) {
case ElementType : : Image : element = ImageElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : Animation : element = AnimationElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : HScrollImage : element = HScrollImageElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : VScrollImage : element = VScrollImageElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : Line : element = LineElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : ClippedText : element = ClippedTextElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : HScrollText : element = HScrollTextElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : CurrentTime : element = CurrentTimeElement : : parseJSON ( jElement , formatVersion ) ; break ;
default : throw std : : runtime_error ( std : : format ( " Unsupported element type {:s} encountered while parsing a section " ,
jElement . at ( " type " ) . get < std : : string > ( ) ) ) ;
}
section - > m_elements . push_back ( std : : move ( element ) ) ;
}
return section ;
}
TimeBasedDrawnSection : : ~ TimeBasedDrawnSection ( ) {
TimeBasedDrawnSection : : ~ TimeBasedDrawnSection ( ) {
}
}
@ -1728,6 +2160,21 @@ std::size_t TimeBasedDrawnSection::serializeTo(std::span<std::byte> target, std:
return pos ;
return pos ;
}
}
nlohmann : : json TimeBasedDrawnSection : : serializeJSON ( std : : uint32_t formatVersion ) const {
nlohmann : : json result ;
result [ " type " ] = " TimeBasedDrawn " ;
result [ " flags " ] [ " drawOnFront " ] = m_drawOnFront ;
result [ " flags " ] [ " drawOnBack " ] = m_drawOnBack ;
result [ " flags " ] [ " clearBeforeDrawing " ] = m_clearBeforeDrawing ;
result [ " startTimestamp " ] = m_startTimestamp ;
result [ " endTimestamp " ] = m_endTimestamp ;
result [ " elements " ] = nlohmann : : json : : array ( ) ;
for ( auto const & element : m_elements ) {
result [ " elements " ] . push_back ( element - > serializeJSON ( formatVersion ) ) ;
}
return result ;
}
std : : expected < std : : unique_ptr < TimeBasedDrawnSection > , ParseError > TimeBasedDrawnSection : : parse ( std : : span < std : : byte const > & buffer , std : : uint32_t formatVersion ) {
std : : expected < std : : unique_ptr < TimeBasedDrawnSection > , ParseError > TimeBasedDrawnSection : : parse ( std : : span < std : : byte const > & buffer , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : ignore = formatVersion ;
@ -1796,6 +2243,42 @@ std::expected<std::unique_ptr<TimeBasedDrawnSection>, ParseError> TimeBasedDrawn
return section ;
return section ;
}
}
std : : unique_ptr < TimeBasedDrawnSection > TimeBasedDrawnSection : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
bool drawOnFront = j . at ( " flags " ) . at ( " drawOnFront " ) ;
bool drawOnBack = j . at ( " flags " ) . at ( " drawOnBack " ) ;
bool clearBeforeDrawing = j . at ( " flags " ) . at ( " clearBeforeDrawing " ) ;
std : : uint64_t startTimestamp = j . at ( " startTimestamp " ) ;
std : : uint64_t endTimestamp = j . at ( " endTimestamp " ) ;
auto section = std : : make_unique < TimeBasedDrawnSection > ( ) ;
section - > setDrawOnFront ( drawOnFront ) ;
section - > setDrawOnBack ( drawOnBack ) ;
section - > setClearBeforeDrawing ( clearBeforeDrawing ) ;
section - > setStartTimestamp ( startTimestamp ) ;
section - > setEndTimestamp ( endTimestamp ) ;
std : : size_t const elementCount = j . at ( " elements " ) . size ( ) ;
for ( std : : size_t i = 0 ; i < elementCount ; + + i ) {
nlohmann : : json const & jElement = j . at ( " elements " ) . at ( i ) ;
ElementType type = jElement . at ( " type " ) ;
std : : unique_ptr < Element > element ;
switch ( type ) {
case ElementType : : Image : element = ImageElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : Animation : element = AnimationElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : HScrollImage : element = HScrollImageElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : VScrollImage : element = VScrollImageElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : Line : element = LineElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : ClippedText : element = ClippedTextElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : HScrollText : element = HScrollTextElement : : parseJSON ( jElement , formatVersion ) ; break ;
case ElementType : : CurrentTime : element = CurrentTimeElement : : parseJSON ( jElement , formatVersion ) ; break ;
default : throw std : : runtime_error ( std : : format ( " Unsupported element type {:s} encountered while parsing a section " ,
jElement . at ( " type " ) . get < std : : string > ( ) ) ) ;
}
section - > m_elements . push_back ( std : : move ( element ) ) ;
}
return section ;
}
CustomFontSection : : ~ CustomFontSection ( ) {
CustomFontSection : : ~ CustomFontSection ( ) {
}
}
@ -1817,6 +2300,8 @@ std::uint32_t CustomFontSection::minimumFormatVersion() const {
}
}
std : : size_t CustomFontSection : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : size_t CustomFontSection : : serializeTo ( std : : span < std : : byte > target , std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
pos = writeU8LE ( target , pos , static_cast < std : : uint16_t > ( SectionType : : AlwaysDrawn ) ) ;
pos = writeU8LE ( target , pos , static_cast < std : : uint16_t > ( SectionType : : AlwaysDrawn ) ) ;
// Will be replaced later
// Will be replaced later
@ -1829,6 +2314,15 @@ std::size_t CustomFontSection::serializeTo(std::span<std::byte> target, std::uin
return pos ;
return pos ;
}
}
nlohmann : : json CustomFontSection : : serializeJSON ( std : : uint32_t formatVersion ) const {
std : : ignore = formatVersion ;
nlohmann : : json result ;
result [ " type " ] = " CustomFont " ;
result [ " data " ] = base64Encode ( m_fontData ) ;
return result ;
}
std : : expected < std : : unique_ptr < CustomFontSection > , ParseError > CustomFontSection : : parse ( std : : span < std : : byte const > & buffer , std : : uint32_t formatVersion ) {
std : : expected < std : : unique_ptr < CustomFontSection > , ParseError > CustomFontSection : : parse ( std : : span < std : : byte const > & buffer , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
std : : ignore = formatVersion ;
@ -1867,6 +2361,16 @@ std::expected<std::unique_ptr<CustomFontSection>, ParseError> CustomFontSection:
return section ;
return section ;
}
}
std : : unique_ptr < CustomFontSection > CustomFontSection : : parseJSON ( nlohmann : : json const & j , std : : uint32_t formatVersion ) {
std : : ignore = formatVersion ;
auto fontData = base64Decode ( j . at ( " data " ) . get < std : : string > ( ) ) ;
auto section = std : : make_unique < CustomFontSection > ( ) ;
section - > setFontData ( fontData ) ;
return section ;
}
std : : size_t serializeFile ( std : : span < std : : byte > & buffer , File const & file ) {
std : : size_t serializeFile ( std : : span < std : : byte > & buffer , File const & file ) {
std : : size_t pos = 0 ;
std : : size_t pos = 0 ;
std : : uint32_t formatVersion = 1 ;
std : : uint32_t formatVersion = 1 ;
@ -1891,6 +2395,20 @@ std::size_t serializeFile(std::span<std::byte>& buffer, File const& file) {
return pos ;
return pos ;
}
}
nlohmann : : json serializeFileJSON ( File const & file ) {
std : : uint32_t formatVersion = 1 ;
for ( auto const & section : file . sections ) {
formatVersion = std : : max ( formatVersion , section - > minimumFormatVersion ( ) ) ;
}
nlohmann : : json result ;
result [ " version " ] = formatVersion ;
result [ " sections " ] = nlohmann : : json : : array ( ) ;
for ( auto const & section : file . sections ) {
result [ " sections " ] . push_back ( section - > serializeJSON ( formatVersion ) ) ;
}
return result ;
}
std : : expected < File , ParseError > parseFile ( std : : span < std : : byte const > data ) {
std : : expected < File , ParseError > parseFile ( std : : span < std : : byte const > data ) {
auto magic = readU32LE ( data ) ;
auto magic = readU32LE ( data ) ;
if ( ! magic ) {
if ( ! magic ) {
@ -1943,4 +2461,113 @@ std::expected<File, ParseError> parseFile(std::span<std::byte const> data) {
return result ;
return result ;
}
}
File parseFileJSON ( nlohmann : : json const & j ) {
File result ;
std : : uint32_t version = j . at ( " version " ) ;
std : : size_t const sectionCount = j . at ( " sections " ) . size ( ) ;
for ( std : : size_t i = 0 ; i < sectionCount ; + + i ) {
nlohmann : : json const & jSection = j . at ( " sections " ) . at ( i ) ;
SectionType sectionType = jSection . at ( " type " ) ;
std : : unique_ptr < Section > section ;
switch ( sectionType ) {
case SectionType : : AlwaysDrawn : section = AlwaysDrawnSection : : parseJSON ( jSection , version ) ; break ;
case SectionType : : TimeBasedDrawn : section = TimeBasedDrawnSection : : parseJSON ( jSection , version ) ; break ;
case SectionType : : CustomFont : section = CustomFontSection : : parseJSON ( jSection , version ) ; break ;
default : throw std : : runtime_error ( std : : format ( " Unsupported section type {:s} encountered while parsing a file " ,
jSection . at ( " type " ) . get < std : : string > ( ) ) ) ;
}
result . sections . push_back ( std : : move ( section ) ) ;
}
return result ;
}
constexpr static char const * const Base64Alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
constexpr static std : : int8_t const Base64ParseLookup [ 256 ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 62 , - 1 , - 1 , - 1 , 63 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , - 1 , - 1 , - 1 , - 2 , - 1 , - 1 , - 1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
std : : string base64Encode ( std : : span < std : : byte const > buffer ) {
std : : string result ;
uint8_t const * data = reinterpret_cast < uint8_t const * > ( buffer . data ( ) ) ;
std : : size_t numberOfBlocks = ( buffer . size ( ) + 2 ) / 3 ;
result . reserve ( numberOfBlocks ) ;
for ( std : : size_t i = 0 ; i < numberOfBlocks ; + + i ) {
std : : size_t ii = i * 3 ;
std : : size_t ni = std : : min ( ii + 3 , buffer . size ( ) ) - ii ;
int c0 = ( ( ( data [ ii + 0 ] > > 2 ) & 0x3f ) < < 0 ) ;
if ( ni = = 3 ) {
int c1 = ( ( ( data [ ii + 0 ] > > 0 ) & 0x03 ) < < 4 )
| ( ( ( data [ ii + 1 ] > > 4 ) & 0x0f ) < < 0 ) ;
int c2 = ( ( ( data [ ii + 1 ] > > 0 ) & 0x0f ) < < 2 )
| ( ( ( data [ ii + 2 ] > > 6 ) & 0x03 ) < < 0 ) ;
int c3 = ( ( ( data [ ii + 2 ] > > 0 ) & 0x3f ) < < 0 ) ;
result . push_back ( Base64Alphabet [ c0 ] ) ;
result . push_back ( Base64Alphabet [ c1 ] ) ;
result . push_back ( Base64Alphabet [ c2 ] ) ;
result . push_back ( Base64Alphabet [ c3 ] ) ;
} else if ( ni = = 2 ) {
int c1 = ( ( ( data [ ii + 0 ] > > 0 ) & 0x03 ) < < 4 )
| ( ( ( data [ ii + 1 ] > > 4 ) & 0x0f ) < < 0 ) ;
int c2 = ( ( ( data [ ii + 1 ] > > 0 ) & 0x0f ) < < 2 ) ;
result . push_back ( Base64Alphabet [ c0 ] ) ;
result . push_back ( Base64Alphabet [ c1 ] ) ;
result . push_back ( Base64Alphabet [ c2 ] ) ;
} else if ( ni = = 1 ) {
int c1 = ( ( ( data [ ii + 0 ] > > 0 ) & 0x03 ) < < 4 ) ;
result . push_back ( Base64Alphabet [ c0 ] ) ;
result . push_back ( Base64Alphabet [ c1 ] ) ;
}
}
return result ;
}
std : : vector < std : : byte > base64Decode ( std : : string_view data ) {
std : : vector < std : : byte > result ;
// This is just an initial estimate
std : : size_t numberOfBlocks = ( data . size ( ) + 3 ) / 4 ;
result . reserve ( numberOfBlocks * 3 ) ;
int state = 0 ;
int currentValue = 0 ;
for ( std : : size_t i = 0 ; i < data . size ( ) ; + + i ) {
int value = Base64ParseLookup [ static_cast < std : : uint8_t > ( data [ i ] ) ] ;
if ( value = = - 2 ) {
// '=': padding at the end
break ;
} else if ( value = = - 1 ) {
// any invalid character (especially whitespace): ignore
continue ;
}
switch ( state ) {
case 0 :
default :
currentValue = value < < 2 ;
break ;
case 1 :
currentValue | = ( value > > 4 ) & 0x03 ;
result . push_back ( static_cast < std : : byte > ( currentValue ) ) ;
currentValue = ( value & 0x0f ) < < 4 ;
break ;
case 2 :
currentValue | = ( value > > 2 ) & 0x0f ;
result . push_back ( static_cast < std : : byte > ( currentValue ) ) ;
currentValue = ( value & 0x03 ) < < 6 ;
break ;
case 3 :
currentValue | = value & 0x3f ;
result . push_back ( static_cast < std : : byte > ( currentValue ) ) ;
currentValue = 0 ;
break ;
}
state = ( state + 1 ) % 4 ;
}
// Ignore any errors here
return result ;
}
} // namespace monoformat
} // namespace monoformat