From ae7baf09809f094547c708d5f7b931845575c1ce Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 28 Dec 2021 16:52:22 -0600 Subject: [PATCH] Load packets using a packet factory --- .../scwx/wsr88d/rpg/packet_factory.hpp | 30 ++++++++ wxdata/source/scwx/wsr88d/level3_file.cpp | 16 ++-- .../source/scwx/wsr88d/rpg/packet_factory.cpp | 73 +++++++++++++++++++ .../wsr88d/rpg/product_symbology_block.cpp | 50 +++++++++++-- 4 files changed, 155 insertions(+), 14 deletions(-) create mode 100644 wxdata/include/scwx/wsr88d/rpg/packet_factory.hpp create mode 100644 wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp diff --git a/wxdata/include/scwx/wsr88d/rpg/packet_factory.hpp b/wxdata/include/scwx/wsr88d/rpg/packet_factory.hpp new file mode 100644 index 00000000..889b8c3d --- /dev/null +++ b/wxdata/include/scwx/wsr88d/rpg/packet_factory.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +class PacketFactory +{ +private: + explicit PacketFactory() = delete; + ~PacketFactory() = delete; + + PacketFactory(const PacketFactory&) = delete; + PacketFactory& operator=(const PacketFactory&) = delete; + + PacketFactory(PacketFactory&&) noexcept = delete; + PacketFactory& operator=(PacketFactory&&) noexcept = delete; + +public: + static std::shared_ptr Create(std::istream& is); +}; + +} // 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 08200c8c..7302a715 100644 --- a/wxdata/source/scwx/wsr88d/level3_file.cpp +++ b/wxdata/source/scwx/wsr88d/level3_file.cpp @@ -32,7 +32,7 @@ public: tabularBlock_ {} {}; ~Level3FileImpl() = default; - void LoadBlocks(std::istream& is); + bool LoadBlocks(std::istream& is); rpg::WmoHeader wmoHeader_; rpg::Level3MessageHeader messageHeader_; @@ -123,7 +123,7 @@ bool Level3File::LoadData(std::istream& is) << logPrefix_ << "Decompressed data size = " << bytesCopied << " bytes"; - p->LoadBlocks(ss); + dataValid = p->LoadBlocks(ss); } catch (const boost::iostreams::bzip2_error& ex) { @@ -136,15 +136,19 @@ bool Level3File::LoadData(std::istream& is) } else { - p->LoadBlocks(is); + dataValid = p->LoadBlocks(is); } } return dataValid; } -void Level3FileImpl::LoadBlocks(std::istream& is) +bool Level3FileImpl::LoadBlocks(std::istream& is) { + bool symbologyValid = true; + bool graphicValid = true; + bool tabularValid = true; + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Loading Blocks"; std::streampos offsetBasePos = is.tellg(); @@ -159,8 +163,6 @@ void Level3FileImpl::LoadBlocks(std::istream& is) if (offsetToSymbology >= offsetBase) { - bool symbologyValid; - symbologyBlock_ = std::make_shared(); is.seekg(offsetToSymbology - offsetBase, std::ios_base::cur); @@ -197,6 +199,8 @@ void Level3FileImpl::LoadBlocks(std::istream& is) << logPrefix_ << "Tabular alphanumeric block found: " << offsetToTabular; } + + return (symbologyValid && graphicValid && tabularValid); } } // namespace wsr88d diff --git a/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp new file mode 100644 index 00000000..e689a035 --- /dev/null +++ b/wxdata/source/scwx/wsr88d/rpg/packet_factory.cpp @@ -0,0 +1,73 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace scwx +{ +namespace wsr88d +{ +namespace rpg +{ + +static const std::string logPrefix_ = "[scwx::wsr88d::rpg::packet_factory] "; + +typedef std::function(std::istream&)> + CreateMessageFunction; + +static const std::unordered_map create_ { + {1, TextAndSpecialSymbolPacket::Create}, + {2, TextAndSpecialSymbolPacket::Create}, + {6, LinkedVectorPacket::Create}, + {7, UnlinkedVectorPacket::Create}, + {8, TextAndSpecialSymbolPacket::Create}, + {9, LinkedVectorPacket::Create}, + {10, UnlinkedVectorPacket::Create}, + {0x0802, SetColorLevelPacket::Create}, + {0x0E03, LinkedContourVectorPacket::Create}, + {0x3501, UnlinkedContourVectorPacket::Create}}; + +std::shared_ptr PacketFactory::Create(std::istream& is) +{ + std::shared_ptr packet = nullptr; + bool packetValid = true; + + uint16_t packetCode; + + is.read(reinterpret_cast(&packetCode), 2); + packetCode = ntohs(packetCode); + + if (is.eof()) + { + packetValid = false; + } + + is.seekg(-2, std::ios_base::cur); + + if (packetValid && create_.find(packetCode) == create_.end()) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Unknown packet code: " << packetCode << " (0x" + << std::hex << packetCode << std::dec << ")"; + packetValid = false; + } + + if (packetValid) + { + packet = create_.at(packetCode)(is); + } + + return packet; +} + +} // namespace rpg +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp b/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp index 3114ffbc..4d5f3d12 100644 --- a/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/product_symbology_block.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -26,6 +27,8 @@ public: int16_t blockId_; uint32_t lengthOfBlock_; uint16_t numberOfLayers_; + + std::vector>> layerList_; }; ProductSymbologyBlock::ProductSymbologyBlock() : @@ -102,25 +105,56 @@ bool ProductSymbologyBlock::Parse(std::istream& is) { int16_t layerDivider; uint32_t lengthOfDataLayer; - uint16_t packetCode; + uint32_t bytesRead = 0; for (uint16_t i = 0; i < p->numberOfLayers_; i++) { + std::vector> packetList; + is.read(reinterpret_cast(&layerDivider), 2); is.read(reinterpret_cast(&lengthOfDataLayer), 4); layerDivider = ntohs(layerDivider); lengthOfDataLayer = ntohl(lengthOfDataLayer); - is.read(reinterpret_cast(&packetCode), 2); - packetCode = ntohs(packetCode); - is.seekg(-2, std::ios_base::cur); + std::streampos layerStart = is.tellg(); + std::streampos layerEnd = + layerStart + static_cast(lengthOfDataLayer); - BOOST_LOG_TRIVIAL(debug) - << logPrefix_ << "Reading packet: " << packetCode; + while (bytesRead < lengthOfDataLayer) + { + std::shared_ptr packet = PacketFactory::Create(is); + if (packet != nullptr) + { + packetList.push_back(packet); + bytesRead += static_cast(packet->data_size()); + } + else + { + break; + } + } - // TODO: Read packets - is.seekg(lengthOfDataLayer, std::ios_base::cur); + if (bytesRead < lengthOfDataLayer) + { + BOOST_LOG_TRIVIAL(trace) + << logPrefix_ + << "Layer bytes read smaller than size: " << bytesRead << " < " + << lengthOfDataLayer << " bytes"; + blockValid = false; + is.seekg(layerEnd, std::ios_base::beg); + } + if (bytesRead > lengthOfDataLayer) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ + << "Layer bytes read larger than size: " << bytesRead << " > " + << lengthOfDataLayer << " bytes"; + blockValid = false; + is.seekg(layerEnd, std::ios_base::beg); + } + + p->layerList_.push_back(std::move(packetList)); } }