Text product message fixes to support IEM

This commit is contained in:
Dan Paulat 2025-02-02 01:34:35 -06:00
parent 2720ad6a38
commit e6cfef06a7
2 changed files with 34 additions and 28 deletions

View file

@ -11,9 +11,7 @@
#include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/trim.hpp>
#include <re2/re2.h> #include <re2/re2.h>
namespace scwx namespace scwx::awips
{
namespace awips
{ {
static const std::string logPrefix_ = "scwx::awips::text_product_message"; static const std::string logPrefix_ = "scwx::awips::text_product_message";
@ -49,6 +47,11 @@ public:
{ {
} }
~TextProductMessageImpl() = default; ~TextProductMessageImpl() = default;
TextProductMessageImpl(const TextProductMessageImpl&) = delete;
TextProductMessageImpl& operator=(const TextProductMessageImpl&) = delete;
TextProductMessageImpl(const TextProductMessageImpl&&) = delete;
TextProductMessageImpl& operator=(const TextProductMessageImpl&&) = delete;
std::string messageContent_; std::string messageContent_;
std::shared_ptr<WmoHeader> wmoHeader_; std::shared_ptr<WmoHeader> wmoHeader_;
@ -232,7 +235,7 @@ bool TextProductMessage::Parse(std::istream& is)
if (i == 0) if (i == 0)
{ {
if (is.peek() != '\r') if (is.peek() != '\r' && is.peek() != '\n')
{ {
segment->header_ = TryParseSegmentHeader(is); segment->header_ = TryParseSegmentHeader(is);
} }
@ -318,8 +321,8 @@ bool TextProductMessage::Parse(std::istream& is)
return dataValid; return dataValid;
} }
void ParseCodedInformation(std::shared_ptr<Segment> segment, void ParseCodedInformation(const std::shared_ptr<Segment>& segment,
const std::string& wfo) const std::string& wfo)
{ {
typedef std::vector<std::string>::const_iterator StringIterator; typedef std::vector<std::string>::const_iterator StringIterator;
@ -352,8 +355,8 @@ void ParseCodedInformation(std::shared_ptr<Segment> segment,
codedLocationEnd = it; codedLocationEnd = it;
} }
else if (codedMotionBegin == productContent.cend() && if (codedMotionBegin == productContent.cend() &&
it->starts_with("TIME...MOT...LOC")) it->starts_with("TIME...MOT...LOC"))
{ {
codedMotionBegin = it; codedMotionBegin = it;
} }
@ -366,8 +369,7 @@ void ParseCodedInformation(std::shared_ptr<Segment> segment,
codedMotionEnd = it; codedMotionEnd = it;
} }
else if (!segment->observed_ && if (!segment->observed_ && it->find("...OBSERVED") != std::string::npos)
it->find("...OBSERVED") != std::string::npos)
{ {
segment->observed_ = true; segment->observed_ = true;
} }
@ -378,6 +380,8 @@ void ParseCodedInformation(std::shared_ptr<Segment> segment,
segment->tornadoPossible_ = true; segment->tornadoPossible_ = true;
} }
// Assignment of an iterator permitted
// NOLINTBEGIN(bugprone-assignment-in-if-condition)
else if (segment->threatCategory_ == ibw::ThreatCategory::Base && else if (segment->threatCategory_ == ibw::ThreatCategory::Base &&
(threatTagIt = std::find_if(kThreatCategoryTags.cbegin(), (threatTagIt = std::find_if(kThreatCategoryTags.cbegin(),
kThreatCategoryTags.cend(), kThreatCategoryTags.cend(),
@ -385,6 +389,7 @@ void ParseCodedInformation(std::shared_ptr<Segment> segment,
return it->starts_with(tag); return it->starts_with(tag);
})) != kThreatCategoryTags.cend() && })) != kThreatCategoryTags.cend() &&
it->length() > threatTagIt->length()) it->length() > threatTagIt->length())
// NOLINTEND(bugprone-assignment-in-if-condition)
{ {
const std::string threatCategoryName = const std::string threatCategoryName =
it->substr(threatTagIt->length()); it->substr(threatTagIt->length());
@ -458,7 +463,7 @@ void SkipBlankLines(std::istream& is)
{ {
std::string line; std::string line;
while (is.peek() == '\r') while (is.peek() == '\r' || is.peek() == '\n')
{ {
util::getline(is, line); util::getline(is, line);
} }
@ -513,7 +518,7 @@ std::vector<std::string> TryParseMndHeader(std::istream& is)
std::string line; std::string line;
std::streampos isBegin = is.tellg(); std::streampos isBegin = is.tellg();
while (!is.eof() && is.peek() != '\r') while (!is.eof() && is.peek() != '\r' && is.peek() != '\n')
{ {
util::getline(is, line); util::getline(is, line);
mndHeader.push_back(line); mndHeader.push_back(line);
@ -546,7 +551,7 @@ std::vector<std::string> TryParseOverviewBlock(std::istream& is)
if (is.peek() == '.') if (is.peek() == '.')
{ {
while (!is.eof() && is.peek() != '\r') while (!is.eof() && is.peek() != '\r' && is.peek() != '\n')
{ {
util::getline(is, line); util::getline(is, line);
overviewBlock.push_back(line); overviewBlock.push_back(line);
@ -576,7 +581,7 @@ std::optional<SegmentHeader> TryParseSegmentHeader(std::istream& is)
header->ugcString_.push_back(line); header->ugcString_.push_back(line);
// If UGC is multi-line, continue parsing // If UGC is multi-line, continue parsing
while (!is.eof() && is.peek() != '\r' && while (!is.eof() && is.peek() != '\r' && is.peek() != '\n' &&
!RE2::PartialMatch(line, *reUgcExpiration)) !RE2::PartialMatch(line, *reUgcExpiration))
{ {
util::getline(is, line); util::getline(is, line);
@ -595,7 +600,7 @@ std::optional<SegmentHeader> TryParseSegmentHeader(std::istream& is)
header->vtecString_.push_back(std::move(*vtec)); header->vtecString_.push_back(std::move(*vtec));
} }
while (!is.eof() && is.peek() != '\r') while (!is.eof() && is.peek() != '\r' && is.peek() != '\n')
{ {
util::getline(is, line); util::getline(is, line);
if (!RE2::PartialMatch(line, *reDateTimeString)) if (!RE2::PartialMatch(line, *reDateTimeString))
@ -640,10 +645,8 @@ std::optional<Vtec> TryParseVtecString(std::istream& is)
if (RE2::PartialMatch(line, *rePVtecString)) if (RE2::PartialMatch(line, *rePVtecString))
{ {
bool vtecValid; vtec = Vtec();
bool vtecValid = vtec->pVtec_.Parse(line);
vtec = Vtec();
vtecValid = vtec->pVtec_.Parse(line);
isBegin = is.tellg(); isBegin = is.tellg();
@ -687,5 +690,4 @@ std::shared_ptr<TextProductMessage> TextProductMessage::Create(std::istream& is)
return message; return message;
} }
} // namespace awips } // namespace scwx::awips
} // namespace scwx

View file

@ -1,8 +1,7 @@
#include <scwx/util/streams.hpp> #include <scwx/util/streams.hpp>
#include <scwx/common/characters.hpp>
namespace scwx namespace scwx::util
{
namespace util
{ {
std::istream& getline(std::istream& is, std::string& t) std::istream& getline(std::istream& is, std::string& t)
@ -17,7 +16,8 @@ std::istream& getline(std::istream& is, std::string& t)
int c = sb->sbumpc(); int c = sb->sbumpc();
switch (c) switch (c)
{ {
case '\n': return is; case '\n':
return is;
case '\r': case '\r':
while (sb->sgetc() == '\r') while (sb->sgetc() == '\r')
@ -30,6 +30,10 @@ std::istream& getline(std::istream& is, std::string& t)
} }
return is; return is;
case common::Characters::ETX:
sb->sungetc();
return is;
case std::streambuf::traits_type::eof(): case std::streambuf::traits_type::eof():
if (t.empty()) if (t.empty())
{ {
@ -37,10 +41,10 @@ std::istream& getline(std::istream& is, std::string& t)
} }
return is; return is;
default: t += static_cast<char>(c); default:
t += static_cast<char>(c);
} }
} }
} }
} // namespace util } // namespace scwx::util
} // namespace scwx