From 0b063f6e8caf3a47eff4e44dcee4eb46d1ef375f Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 12 Jan 2022 18:05:33 -0600 Subject: [PATCH] Tabular alphanumeric block --- .../wsr88d/rpg/tabular_alphanumeric_block.hpp | 44 ++++ wxdata/source/scwx/wsr88d/level3_file.cpp | 15 +- .../scwx/wsr88d/rpg/level3_message_header.cpp | 2 +- .../wsr88d/rpg/tabular_alphanumeric_block.cpp | 209 ++++++++++++++++++ wxdata/wxdata.cmake | 2 + 5 files changed, 267 insertions(+), 5 deletions(-) create mode 100644 wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp create mode 100644 wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp diff --git a/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp b/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp new file mode 100644 index 00000000..8c39a8db --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class TabularAlphanumericBlockImpl; + +class TabularAlphanumericBlock : public Message +{ +public: + explicit TabularAlphanumericBlock(); + ~TabularAlphanumericBlock(); + + TabularAlphanumericBlock(const TabularAlphanumericBlock&) = delete; + TabularAlphanumericBlock& + operator=(const TabularAlphanumericBlock&) = delete; + + TabularAlphanumericBlock(TabularAlphanumericBlock&&) noexcept; + TabularAlphanumericBlock& operator=(TabularAlphanumericBlock&&) 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 79c406c1..3850d00f 100644 --- a/wxdata/source/scwx/wsr88d/level3_file.cpp +++ b/wxdata/source/scwx/wsr88d/level3_file.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,7 @@ public: std::shared_ptr descriptionBlock_; std::shared_ptr symbologyBlock_; std::shared_ptr graphicBlock_; - std::shared_ptr tabularBlock_; + std::shared_ptr tabularBlock_; }; Level3File::Level3File() : p(std::make_unique()) {} @@ -304,13 +305,19 @@ bool Level3FileImpl::LoadBlocks(std::istream& is) if (offsetToTabular >= offsetBase) { - // TODO + tabularBlock_ = std::make_shared(); + is.seekg(offsetToTabular - offsetBase, std::ios_base::cur); + tabularValid = tabularBlock_->Parse(is); is.seekg(offsetBasePos, std::ios_base::beg); BOOST_LOG_TRIVIAL(debug) - << logPrefix_ - << "Tabular alphanumeric block found: " << offsetToTabular; + << logPrefix_ << "Tabular alphanumeric block valid: " << tabularValid; + + if (!tabularValid) + { + tabularBlock_ = nullptr; + } } return (symbologyValid && graphicValid && tabularValid); diff --git a/wxdata/source/scwx/wsr88d/rpg/level3_message_header.cpp b/wxdata/source/scwx/wsr88d/rpg/level3_message_header.cpp index 8617edae..53ff5686 100644 --- a/wxdata/source/scwx/wsr88d/rpg/level3_message_header.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/level3_message_header.cpp @@ -126,7 +126,7 @@ bool Level3MessageHeader::Parse(std::istream& is) << logPrefix_ << "Invalid message code: " << p->messageCode_; headerValid = false; } - if (p->dateOfMessage_ < 1u || p->dateOfMessage_ > 32'767u) + if (p->dateOfMessage_ > 32'767u) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Invalid date: " << p->dateOfMessage_; diff --git a/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp b/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp new file mode 100644 index 00000000..73c0552e --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp @@ -0,0 +1,209 @@ +#include +#include +#include +#include + +#include +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = + "[scwx::wsr88d::rpg::tabular_alphanumeric_block] "; + +class TabularAlphanumericBlockImpl +{ +public: + explicit TabularAlphanumericBlockImpl() : + blockDivider1_ {0}, + blockId_ {0}, + lengthOfBlock_ {0}, + messageHeader_ {}, + descriptionBlock_ {}, + blockDivider2_ {0}, + numberOfPages_ {0}, + pageList_ {} + { + } + ~TabularAlphanumericBlockImpl() = default; + + int16_t blockDivider1_; + int16_t blockId_; + uint32_t lengthOfBlock_; + + std::shared_ptr messageHeader_; + std::shared_ptr descriptionBlock_; + + int16_t blockDivider2_; + uint16_t numberOfPages_; + + std::vector> pageList_; +}; + +TabularAlphanumericBlock::TabularAlphanumericBlock() : + Message(), p(std::make_unique()) +{ +} +TabularAlphanumericBlock::~TabularAlphanumericBlock() = default; + +TabularAlphanumericBlock::TabularAlphanumericBlock( + TabularAlphanumericBlock&&) noexcept = default; +TabularAlphanumericBlock& TabularAlphanumericBlock::operator=( + TabularAlphanumericBlock&&) noexcept = default; + +int16_t TabularAlphanumericBlock::block_divider() const +{ + return p->blockDivider1_; +} + +size_t TabularAlphanumericBlock::data_size() const +{ + return p->lengthOfBlock_; +} + +bool TabularAlphanumericBlock::Parse(std::istream& is) +{ + bool blockValid = true; + + const std::streampos blockStart = is.tellg(); + + is.read(reinterpret_cast(&p->blockDivider1_), 2); + is.read(reinterpret_cast(&p->blockId_), 2); + is.read(reinterpret_cast(&p->lengthOfBlock_), 4); + + p->blockDivider1_ = ntohs(p->blockDivider1_); + p->blockId_ = ntohs(p->blockId_); + p->lengthOfBlock_ = ntohl(p->lengthOfBlock_); + + if (is.eof()) + { + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; + blockValid = false; + } + else + { + if (p->blockDivider1_ != -1) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid first block divider: " << p->blockDivider1_; + blockValid = false; + } + if (p->blockId_ != 3) + { + 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 (blockValid) + { + p->messageHeader_ = std::make_shared(); + blockValid = p->messageHeader_->Parse(is); + + if (!blockValid) + { + p->messageHeader_ = nullptr; + } + } + + if (blockValid) + { + p->descriptionBlock_ = std::make_shared(); + blockValid = p->descriptionBlock_->Parse(is); + + if (!blockValid) + { + p->descriptionBlock_ = nullptr; + } + } + + if (blockValid) + { + is.read(reinterpret_cast(&p->blockDivider2_), 2); + is.read(reinterpret_cast(&p->numberOfPages_), 2); + + p->blockDivider2_ = ntohs(p->blockDivider2_); + p->numberOfPages_ = ntohs(p->numberOfPages_); + + if (p->blockDivider2_ != -1) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid second block divider: " << p->blockDivider2_; + 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 numberOfCharacters; + + for (uint16_t i = 0; i < p->numberOfPages_; i++) + { + std::vector lineList; + + while (!is.eof()) + { + is.read(reinterpret_cast(&numberOfCharacters), 2); + numberOfCharacters = ntohs(numberOfCharacters); + + if (static_cast(numberOfCharacters) == -1) + { + // End of page + break; + } + else if (numberOfCharacters > 80) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Invalid number of characters: " << numberOfCharacters + << " (Page " << (i + 1) << ")"; + blockValid = false; + break; + } + + std::string line; + line.resize(numberOfCharacters); + is.read(line.data(), numberOfCharacters); + + lineList.push_back(std::move(line)); + } + + p->pageList_.push_back(std::move(lineList)); + } + } + + 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 287f15c5..87ba8afe 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -72,6 +72,7 @@ set(HDR_WSR88D_RPG include/scwx/wsr88d/rpg/ccb_header.hpp include/scwx/wsr88d/rpg/special_graphic_symbol_packet.hpp include/scwx/wsr88d/rpg/sti_circle_symbol_packet.hpp include/scwx/wsr88d/rpg/storm_id_symbol_packet.hpp + include/scwx/wsr88d/rpg/tabular_alphanumeric_block.hpp include/scwx/wsr88d/rpg/text_and_special_symbol_packet.hpp include/scwx/wsr88d/rpg/unlinked_contour_vector_packet.hpp include/scwx/wsr88d/rpg/unlinked_vector_packet.hpp @@ -104,6 +105,7 @@ set(SRC_WSR88D_RPG source/scwx/wsr88d/rpg/ccb_header.cpp source/scwx/wsr88d/rpg/special_graphic_symbol_packet.cpp source/scwx/wsr88d/rpg/sti_circle_symbol_packet.cpp source/scwx/wsr88d/rpg/storm_id_symbol_packet.cpp + source/scwx/wsr88d/rpg/tabular_alphanumeric_block.cpp source/scwx/wsr88d/rpg/text_and_special_symbol_packet.cpp source/scwx/wsr88d/rpg/unlinked_contour_vector_packet.cpp source/scwx/wsr88d/rpg/unlinked_vector_packet.cpp