From add6c41016d3271025f11b961d9ffbcbf324dd47 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 12 Jan 2022 01:15:41 -0600 Subject: [PATCH] Graphic alphanumeric block --- .../wsr88d/rpg/graphic_alphanumeric_block.hpp | 44 +++++ wxdata/source/scwx/wsr88d/level3_file.cpp | 29 +-- .../wsr88d/rpg/graphic_alphanumeric_block.cpp | 187 ++++++++++++++++++ wxdata/wxdata.cmake | 2 + 4 files changed, 251 insertions(+), 11 deletions(-) create mode 100644 wxdata/include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp create mode 100644 wxdata/source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp diff --git a/wxdata/include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp b/wxdata/include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp new file mode 100644 index 00000000..0e67e38b --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class GraphicAlphanumericBlockImpl; + +class GraphicAlphanumericBlock : public Message +{ +public: + explicit GraphicAlphanumericBlock(); + ~GraphicAlphanumericBlock(); + + GraphicAlphanumericBlock(const GraphicAlphanumericBlock&) = delete; + GraphicAlphanumericBlock& + operator=(const GraphicAlphanumericBlock&) = delete; + + GraphicAlphanumericBlock(GraphicAlphanumericBlock&&) noexcept; + GraphicAlphanumericBlock& operator=(GraphicAlphanumericBlock&&) noexcept; + + int16_t block_divider() const; + + size_t data_size() const override; + + bool Parse(std::istream& is); + + static constexpr size_t SIZE = 102u; + +private: + std::unique_ptr p; +}; + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/level3_file.cpp b/wxdata/source/scwx/wsr88d/level3_file.cpp index 1bd68596..79c406c1 100644 --- a/wxdata/source/scwx/wsr88d/level3_file.cpp +++ b/wxdata/source/scwx/wsr88d/level3_file.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -39,14 +40,14 @@ public: bool LoadFileData(std::istream& is); bool LoadBlocks(std::istream& is); - std::shared_ptr wmoHeader_; - std::shared_ptr ccbHeader_; - std::shared_ptr innerHeader_; - std::shared_ptr messageHeader_; - std::shared_ptr descriptionBlock_; - std::shared_ptr symbologyBlock_; - std::shared_ptr graphicBlock_; - std::shared_ptr tabularBlock_; + std::shared_ptr wmoHeader_; + std::shared_ptr ccbHeader_; + std::shared_ptr innerHeader_; + std::shared_ptr messageHeader_; + std::shared_ptr descriptionBlock_; + std::shared_ptr symbologyBlock_; + std::shared_ptr graphicBlock_; + std::shared_ptr tabularBlock_; }; Level3File::Level3File() : p(std::make_unique()) {} @@ -286,13 +287,19 @@ bool Level3FileImpl::LoadBlocks(std::istream& is) if (offsetToGraphic >= offsetBase) { - // TODO + graphicBlock_ = std::make_shared(); + is.seekg(offsetToGraphic - offsetBase, std::ios_base::cur); + graphicValid = graphicBlock_->Parse(is); is.seekg(offsetBasePos, std::ios_base::beg); BOOST_LOG_TRIVIAL(debug) - << logPrefix_ - << "Graphic alphanumeric block found: " << offsetToGraphic; + << logPrefix_ << "Graphic alphanumeric block valid: " << graphicValid; + + if (!graphicValid) + { + graphicBlock_ = nullptr; + } } if (offsetToTabular >= offsetBase) diff --git a/wxdata/source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp b/wxdata/source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp new file mode 100644 index 00000000..8786efee --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp @@ -0,0 +1,187 @@ +#include +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::graphic_alphanumeric_block] "; + +class GraphicAlphanumericBlockImpl +{ +public: + explicit GraphicAlphanumericBlockImpl() : + blockDivider_ {0}, + blockId_ {0}, + lengthOfBlock_ {0}, + numberOfPages_ {0}, + pageList_ {} + { + } + ~GraphicAlphanumericBlockImpl() = default; + + int16_t blockDivider_; + int16_t blockId_; + uint32_t lengthOfBlock_; + uint16_t numberOfPages_; + + std::vector>> pageList_; +}; + +GraphicAlphanumericBlock::GraphicAlphanumericBlock() : + Message(), p(std::make_unique()) +{ +} +GraphicAlphanumericBlock::~GraphicAlphanumericBlock() = default; + +GraphicAlphanumericBlock::GraphicAlphanumericBlock( + GraphicAlphanumericBlock&&) noexcept = default; +GraphicAlphanumericBlock& GraphicAlphanumericBlock::operator=( + GraphicAlphanumericBlock&&) noexcept = default; + +int16_t GraphicAlphanumericBlock::block_divider() const +{ + return p->blockDivider_; +} + +size_t GraphicAlphanumericBlock::data_size() const +{ + return p->lengthOfBlock_; +} + +bool GraphicAlphanumericBlock::Parse(std::istream& is) +{ + bool blockValid = true; + + const std::streampos blockStart = is.tellg(); + + is.read(reinterpret_cast(&p->blockDivider_), 2); + is.read(reinterpret_cast(&p->blockId_), 2); + is.read(reinterpret_cast(&p->lengthOfBlock_), 4); + is.read(reinterpret_cast(&p->numberOfPages_), 2); + + p->blockDivider_ = ntohs(p->blockDivider_); + p->blockId_ = ntohs(p->blockId_); + p->lengthOfBlock_ = ntohl(p->lengthOfBlock_); + p->numberOfPages_ = ntohs(p->numberOfPages_); + + if (is.eof()) + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; + blockValid = false; + } + else + { + if (p->blockDivider_ != -1) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid block divider: " << p->blockDivider_; + blockValid = false; + } + if (p->blockId_ != 2) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid block ID: " << p->blockId_; + blockValid = false; + } + if (p->lengthOfBlock_ < 10) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid block length: " << p->lengthOfBlock_; + blockValid = false; + } + if (p->numberOfPages_ < 1 || p->numberOfPages_ > 48) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid number of pages: " << p->numberOfPages_; + blockValid = false; + } + } + + if (blockValid) + { + uint16_t pageNumber; + uint16_t lengthOfPage; + + for (uint16_t i = 0; i < p->numberOfPages_; i++) + { + BOOST_LOG_TRIVIAL(trace) << logPrefix_ << "Page " << (i + 1); + + std::vector> packetList; + uint32_t bytesRead = 0; + + is.read(reinterpret_cast(&pageNumber), 2); + is.read(reinterpret_cast(&lengthOfPage), 2); + + pageNumber = ntohs(pageNumber); + lengthOfPage = ntohs(lengthOfPage); + + std::streampos pageStart = is.tellg(); + std::streampos pageEnd = + pageStart + static_cast(lengthOfPage); + + if (pageNumber != i + 1) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Page out of order: Expected " << (i + 1) + << ", found " << pageNumber; + } + + while (bytesRead < lengthOfPage) + { + std::shared_ptr packet = PacketFactory::Create(is); + if (packet != nullptr) + { + packetList.push_back(packet); + bytesRead += static_cast(packet->data_size()); + } + else + { + break; + } + } + + if (bytesRead < lengthOfPage) + { + BOOST_LOG_TRIVIAL(trace) + << logPrefix_ + << "Page bytes read smaller than size: " << bytesRead << " < " + << lengthOfPage << " bytes"; + blockValid = false; + is.seekg(pageEnd, std::ios_base::beg); + } + if (bytesRead > lengthOfPage) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Page bytes read larger than size: " << bytesRead << " > " + << lengthOfPage << " bytes"; + blockValid = false; + is.seekg(pageEnd, std::ios_base::beg); + } + + p->pageList_.push_back(std::move(packetList)); + } + } + + const std::streampos blockEnd = is.tellg(); + if (!ValidateMessage(is, blockEnd - blockStart)) + { + blockValid = false; + } + + return blockValid; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index f19daa30..287f15c5 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -52,6 +52,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/ccb_header.hpp include/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.hpp include/scwx/wsr88d/rpg/digital_radial_data_array_packet.hpp include/scwx/wsr88d/rpg/generic_data_packet.hpp + include/scwx/wsr88d/rpg/graphic_alphanumeric_block.hpp include/scwx/wsr88d/rpg/hda_hail_symbol_packet.hpp include/scwx/wsr88d/rpg/level3_message_header.hpp include/scwx/wsr88d/rpg/linked_contour_vector_packet.hpp @@ -83,6 +84,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/ccb_header.cpp source/scwx/wsr88d/rpg/digital_precipitation_data_array_packet.cpp source/scwx/wsr88d/rpg/digital_radial_data_array_packet.cpp source/scwx/wsr88d/rpg/generic_data_packet.cpp + source/scwx/wsr88d/rpg/graphic_alphanumeric_block.cpp source/scwx/wsr88d/rpg/hda_hail_symbol_packet.cpp source/scwx/wsr88d/rpg/level3_message_header.cpp source/scwx/wsr88d/rpg/linked_contour_vector_packet.cpp