#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