#pragma once #include #include #include #include #include #include "DeviceDataHead.h" #include "DateTimeObject.h" #include "InfoMapItem.h" #include "StringExtensions.h" #include "DateTimeObject.h" namespace Incart::DeviceComplexCommands { class InfoMap final { private: std::map> m_dataMap; uint8_t m_readedTypeHead; public: uint8_t getTypeHead() { return m_readedTypeHead; } size_t size() { return m_dataMap.size(); } void addValue(std::string name_, int value_) { m_dataMap[name_] = std::make_shared(value_); } void addValue(std::string name_, std::wstring value_) { if (!value_.empty()) { m_dataMap[name_] = std::make_shared(value_); } else { remove(name_); } } void addValue(std::string name_, std::string value_) { if (!value_.empty()) { m_dataMap[name_] = std::make_shared(value_); } else { remove(name_); } } void addValue(std::string name_, const Common::DateTimeObject& value_) { m_dataMap[name_] = std::make_shared(value_); } void remove(std::string key_) { auto it = m_dataMap.find(key_); if (it != m_dataMap.end()) { m_dataMap.erase(it); } } void removeAll() { m_dataMap.clear(); } bool contains(std::string key_) { auto it = m_dataMap.find(key_); return it != m_dataMap.end(); } template T getValue(std::string key_) { auto it = m_dataMap.find(key_); std::shared_ptr> item = std::dynamic_pointer_cast>(it->second); return item->data; } std::vector writeToBuffer(EDeviceDataHeadTypes typeHead_, int size_, size_t backOffset_, uint16_t version_ = 0x306) { std::vector data(toBytes()); // формируем голову DeviceDataHead mapHead(DeviceDataHead::create(static_cast(m_dataMap.size()), typeHead_, version_)); mapHead.length = static_cast(mapHead.getHeadLength() + data.size()); std::vector total(mapHead.toByteArray()); total.insert(total.end(), data.begin(), data.end()); uint32_t crc = calcCrc(total, 0, total.size()); Common::ByteArrayProvider::addDWord(crc, total); if (size_ >= 0) { int correctedSize = size_; size_t totalSize = total.size(); if (totalSize > size_ - backOffset_) // получился размер больше, чем _nSize { if (version_ >= 0x306) { for (; totalSize > correctedSize - backOffset_; correctedSize += size_) { } } else { throw std::out_of_range(std::string("Недостаточно места для сохранения InfoMap! (") + std::to_string(total.size()) + "->" + std::to_string(size_ - backOffset_) + ")"); } } std::vector correctedSizeBytes(correctedSize - totalSize, 0); total.insert(total.end(), correctedSizeBytes.begin(), correctedSizeBytes.end()); } return total; } bool readFromBuffer(const std::vector& data_) { int offset; DeviceDataHead mapHead(DeviceDataHead::create(data_, offset)); if ((mapHead.length == 0) || (mapHead.length > data_.size())) { return false; } uint32_t crc = calcCrc(data_, 0, mapHead.length); std::vector crcBytes(data_.begin() + mapHead.length, data_.begin() + mapHead.length + 4); uint32_t readedCrc = Common::ByteArrayProvider::getDWordFromArray(&crcBytes[0], crcBytes.size(), 0); if (readedCrc != crc) { return false; } m_readedTypeHead = static_cast(mapHead.getTypeHead()); uint8_t tagCount = mapHead.getTagCount(); for (uint8_t i = 0; i < tagCount; ++i) { std::string mapKey = extractKey(data_, offset); char tag; std::vector fieldData = extractData(data_, offset, tag); m_dataMap[mapKey] = interpretValue(tag, fieldData); } return true; } private: static uint32_t calcCrc(const std::vector& buffer_, size_t offset_, size_t length_) { uint32_t crc = 1; size_t endBufferIndex = offset_ + length_; for (size_t i = offset_; i < endBufferIndex; ++i) { crc ^= ((buffer_[i] << 12) ^ (buffer_[i] << 5) ^ buffer_[i] ^ (buffer_[i] >> 4) ^ 1); } return crc; } // считывание ключа одного поля static std::string extractKey(const std::vector& data_, int& offset_) { std::vector data; uint8_t currData; while ((currData = data_[offset_++]) != 0) // todo: проверить выход за границы массива { data.push_back(currData); } return Common::StringExtensions::toUtf8StringFromWindows1251(data); } // считывание значения одного поля static std::vector extractData(const std::vector& data_, int& offset_, char& tag_) { uint8_t length = data_[offset_++]; // todo: проверить выход за границы массива tag_ = static_cast(data_[offset_++]); std::vector result(data_.begin() + offset_, data_.begin() + offset_ + length - 1); offset_ += result.size(); return result; } static std::shared_ptr interpretValue(char tag_, const std::vector& fieldData_) { switch(tag_) { case 'd': return std::make_shared(static_cast(Common::ByteArrayProvider::getDWordFromArray(&fieldData_[0], fieldData_.size(), 0))); case 'Q': return std::make_shared(Common::DateTimeObject::fromString(Common::StringExtensions::toUtf8StringFromWindows1251(fieldData_))); case 's': return std::make_shared(Common::StringExtensions::toUtf8StringFromWindows1251(fieldData_)); case 'w': return std::make_shared(Common::StringExtensions::toWStringFromWindows1251(fieldData_)); } return nullptr; } // запись всех полей инфомапа в буфер std::vector toBytes() { std::vector data; for (auto it = m_dataMap.begin(); it != m_dataMap.end(); ++it) { // запись ключа std::vector keyBytes = Common::StringExtensions::toWindows1251FromUtf8(it->first); data.insert(data.end(), keyBytes.begin(), keyBytes.end()); data.push_back('\0'); // запись значения std::vector valueBytes = it->second->toBytes(); data.insert(data.end(), valueBytes.begin(), valueBytes.end()); } return data; } }; } // namespace Incart::DeviceComplexCommands