diff --git a/wxdata/include/scwx/wsr88d/level3_file.hpp b/wxdata/include/scwx/wsr88d/level3_file.hpp new file mode 100644 index 00000000..ad4bda06 --- /dev/null +++ b/wxdata/include/scwx/wsr88d/level3_file.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace scwx +{ +namespace wsr88d +{ + +class Level3FileImpl; + +class Level3File +{ +public: + explicit Level3File(); + ~Level3File(); + + Level3File(const Level3File&) = delete; + Level3File& operator=(const Level3File&) = delete; + + Level3File(Level3File&&) noexcept; + Level3File& operator=(Level3File&&) noexcept; + + bool LoadFile(const std::string& filename); + bool LoadData(std::istream& is); + +private: + std::unique_ptr p; +}; + +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/include/scwx/wsr88d/rpg/level3_message_header.hpp b/wxdata/include/scwx/wsr88d/rpg/level3_message_header.hpp index 0cc870a7..ec954f32 100644 --- a/wxdata/include/scwx/wsr88d/rpg/level3_message_header.hpp +++ b/wxdata/include/scwx/wsr88d/rpg/level3_message_header.hpp @@ -34,7 +34,7 @@ public: bool Parse(std::istream& is); - static const size_t SIZE = 18u; + static constexpr size_t SIZE = 18u; private: std::unique_ptr p; diff --git a/wxdata/source/scwx/wsr88d/level3_file.cpp b/wxdata/source/scwx/wsr88d/level3_file.cpp new file mode 100644 index 00000000..b095193d --- /dev/null +++ b/wxdata/source/scwx/wsr88d/level3_file.cpp @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace scwx +{ +namespace wsr88d +{ + +static const std::string logPrefix_ = "[scwx::wsr88d::level3_file] "; + +class Level3FileImpl +{ +public: + explicit Level3FileImpl() : + wmoHeader_ {}, messageHeader_ {}, description_ {} {}; + ~Level3FileImpl() = default; + + void LoadBlocks(std::istream& is); + + rpg::WmoHeader wmoHeader_; + rpg::Level3MessageHeader messageHeader_; + rpg::ProductDescriptionBlock description_; + + size_t numRecords_; +}; + +Level3File::Level3File() : p(std::make_unique()) {} +Level3File::~Level3File() = default; + +Level3File::Level3File(Level3File&&) noexcept = default; +Level3File& Level3File::operator=(Level3File&&) noexcept = default; + +bool Level3File::LoadFile(const std::string& filename) +{ + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "LoadFile(" << filename << ")"; + bool fileValid = true; + + std::ifstream f(filename, std::ios_base::in | std::ios_base::binary); + if (!f.good()) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Could not open file for reading: " << filename; + fileValid = false; + } + + if (fileValid) + { + fileValid = LoadData(f); + } + + return fileValid; +} + +bool Level3File::LoadData(std::istream& is) +{ + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Loading Data"; + + bool dataValid = p->wmoHeader_.Parse(is); + + if (dataValid) + { + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "Data Type: " << p->wmoHeader_.data_type(); + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "ICAO: " << p->wmoHeader_.icao(); + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "Date/Time: " << p->wmoHeader_.date_time(); + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "Category: " << p->wmoHeader_.product_category(); + + dataValid = p->messageHeader_.Parse(is); + } + + if (dataValid) + { + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "Code: " << p->messageHeader_.message_code(); + + dataValid = p->description_.Parse(is); + } + + if (dataValid) + { + if (p->description_.IsCompressionEnabled()) + { + size_t messageLength = p->messageHeader_.length_of_message(); + size_t prefixLength = + rpg::Level3MessageHeader::SIZE + rpg::ProductDescriptionBlock::SIZE; + size_t recordSize = + (messageLength > prefixLength) ? messageLength - prefixLength : 0; + + boost::iostreams::filtering_streambuf in; + util::rangebuf r(is.rdbuf(), recordSize); + in.push(boost::iostreams::bzip2_decompressor()); + in.push(r); + + try + { + std::stringstream ss; + std::streamsize bytesCopied = boost::iostreams::copy(in, ss); + BOOST_LOG_TRIVIAL(trace) + << logPrefix_ << "Decompressed data size = " << bytesCopied + << " bytes"; + + p->LoadBlocks(ss); + } + catch (const boost::iostreams::bzip2_error& ex) + { + int error = ex.error(); + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Error decompressing data: " << ex.what(); + + dataValid = false; + } + } + else + { + p->LoadBlocks(is); + } + } + + return dataValid; +} + +void Level3FileImpl::LoadBlocks(std::istream& is) +{ + BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Loading Blocks"; + + // TODO +} + +} // namespace wsr88d +} // namespace scwx diff --git a/wxdata/source/scwx/wsr88d/rpg/wmo_header.cpp b/wxdata/source/scwx/wsr88d/rpg/wmo_header.cpp index 189f6668..bf56d480 100644 --- a/wxdata/source/scwx/wsr88d/rpg/wmo_header.cpp +++ b/wxdata/source/scwx/wsr88d/rpg/wmo_header.cpp @@ -150,11 +150,11 @@ bool WmoHeader::Parse(std::istream& is) // Remove delimiters from the end of the line if (!sequenceLine.empty()) { - sequenceLine.erase(sequenceLine.end() - 3); + sequenceLine.erase(sequenceLine.length() - 3); } - wmoLine.erase(wmoLine.end() - 2); - awipsLine.erase(awipsLine.end() - 2); + wmoLine.erase(wmoLine.length() - 2); + awipsLine.erase(awipsLine.length() - 2); } // Transmission Header: