#include #include #include #include namespace scwx { namespace wsr88d { namespace rpg { static const std::string logPrefix_ = "[scwx::wsr88d::rpg::raster_data_packet] "; struct Row { uint16_t numberOfBytes_; std::vector data_; Row() : numberOfBytes_ {0}, data_ {} {} }; class RasterDataPacketImpl { public: explicit RasterDataPacketImpl() : packetCode_ {}, opFlag_ {}, iCoordinateStart_ {}, jCoordinateStart_ {}, xScaleInt_ {}, xScaleFractional_ {}, yScaleInt_ {}, yScaleFractional_ {}, numberOfRows_ {}, packagingDescriptor_ {}, row_ {}, dataSize_ {} {}; ~RasterDataPacketImpl() = default; uint16_t packetCode_; std::array opFlag_; int16_t iCoordinateStart_; int16_t jCoordinateStart_; uint16_t xScaleInt_; uint16_t xScaleFractional_; uint16_t yScaleInt_; uint16_t yScaleFractional_; uint16_t numberOfRows_; uint16_t packagingDescriptor_; // Repeat for each radial std::vector row_; size_t dataSize_; }; RasterDataPacket::RasterDataPacket() : p(std::make_unique()) { } RasterDataPacket::~RasterDataPacket() = default; RasterDataPacket::RasterDataPacket(RasterDataPacket&&) noexcept = default; RasterDataPacket& RasterDataPacket::operator=(RasterDataPacket&&) noexcept = default; uint16_t RasterDataPacket::packet_code() const { return p->packetCode_; } uint16_t RasterDataPacket::op_flag(size_t i) const { return p->opFlag_[i]; } int16_t RasterDataPacket::i_coordinate_start() const { return p->iCoordinateStart_; } int16_t RasterDataPacket::j_coordinate_start() const { return p->jCoordinateStart_; } uint16_t RasterDataPacket::x_scale_int() const { return p->xScaleInt_; } uint16_t RasterDataPacket::x_scale_fractional() const { return p->xScaleFractional_; } uint16_t RasterDataPacket::y_scale_int() const { return p->yScaleInt_; } uint16_t RasterDataPacket::y_scale_fractional() const { return p->yScaleFractional_; } uint16_t RasterDataPacket::number_of_rows() const { return p->numberOfRows_; } uint16_t RasterDataPacket::packaging_descriptor() const { return p->packagingDescriptor_; } size_t RasterDataPacket::data_size() const { return p->dataSize_; } bool RasterDataPacket::Parse(std::istream& is) { bool blockValid = true; size_t bytesRead = 0; is.read(reinterpret_cast(&p->packetCode_), 2); is.read(reinterpret_cast(p->opFlag_.data()), 4); is.read(reinterpret_cast(&p->iCoordinateStart_), 2); is.read(reinterpret_cast(&p->jCoordinateStart_), 2); is.read(reinterpret_cast(&p->xScaleInt_), 2); is.read(reinterpret_cast(&p->xScaleFractional_), 2); is.read(reinterpret_cast(&p->yScaleInt_), 2); is.read(reinterpret_cast(&p->yScaleFractional_), 2); is.read(reinterpret_cast(&p->numberOfRows_), 2); is.read(reinterpret_cast(&p->packagingDescriptor_), 2); bytesRead += 22; p->packetCode_ = ntohs(p->packetCode_); p->iCoordinateStart_ = ntohs(p->iCoordinateStart_); p->jCoordinateStart_ = ntohs(p->jCoordinateStart_); p->xScaleInt_ = ntohs(p->xScaleInt_); p->xScaleFractional_ = ntohs(p->xScaleFractional_); p->yScaleInt_ = ntohs(p->yScaleInt_); p->yScaleFractional_ = ntohs(p->yScaleFractional_); p->numberOfRows_ = ntohs(p->numberOfRows_); p->packagingDescriptor_ = ntohs(p->packagingDescriptor_); SwapArray(p->opFlag_); if (is.eof()) { BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Reached end of file"; blockValid = false; } else { if (p->packetCode_ != 0xBA0F && p->packetCode_ != 0xBA07) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Invalid packet code: " << p->packetCode_; blockValid = false; } if (p->numberOfRows_ < 1 || p->numberOfRows_ > 464) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Invalid number of rows: " << p->numberOfRows_; blockValid = false; } } if (blockValid) { p->row_.resize(p->numberOfRows_); for (uint16_t r = 0; r < p->numberOfRows_; r++) { size_t rowBytesRead = 0; Row& row = p->row_[r]; is.read(reinterpret_cast(&row.numberOfBytes_), 2); bytesRead += 2; row.numberOfBytes_ = ntohs(row.numberOfBytes_); if (row.numberOfBytes_ < 2 || row.numberOfBytes_ > 920 || row.numberOfBytes_ % 2 != 0) { BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Invalid number of bytes in row: " << row.numberOfBytes_ << " (Row " << r << ")"; blockValid = false; break; } // Read row data size_t dataSize = row.numberOfBytes_; row.data_.resize(dataSize); is.read(reinterpret_cast(row.data_.data()), dataSize); bytesRead += dataSize; // If the final byte is 0, truncate it if (row.data_.back() == 0) { row.data_.pop_back(); } } } p->dataSize_ = bytesRead; if (!ValidateMessage(is, bytesRead)) { blockValid = false; } return blockValid; } std::shared_ptr RasterDataPacket::Create(std::istream& is) { std::shared_ptr packet = std::make_shared(); if (!packet->Parse(is)) { packet.reset(); } return packet; } } // namespace rpg } // namespace wsr88d } // namespace scwx