Advertisement
Guest User

Untitled

a guest
Apr 12th, 2018
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 39.37 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cassert>
  3. #include <cctype>
  4. #include <cstring>
  5. #include <optional>
  6. #include <stdexcept>
  7. #include <string>
  8. #include <string_view>
  9. #include <type_traits>
  10. #include <variant>
  11. #include <vector>
  12.  
  13. #include "adsData.h"
  14.  
  15. using namespace std::literals::string_literals;
  16. using namespace std::literals::string_view_literals;
  17.  
  18. AdsVarData::AdsVarData() noexcept : info_() {}
  19.  
  20. AdsVarData::AdsVarData(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset, SizeType index = 0u - 1u)
  21.     : info_{info}, group_{group}, offset_{offset}, index_{index}
  22. {}
  23.  
  24. namespace
  25. {
  26.     std::string operator+(std::string lhs, std::string_view rhs)
  27.     {
  28.         return std::move(lhs.append(rhs.data(), rhs.size()));
  29.     }
  30.     std::string operator+(std::string_view lhs, std::string_view rhs)
  31.     {
  32.         std::string result;
  33.         result.reserve(lhs.size() + rhs.size());
  34.         result.assign(lhs.data(), lhs.size()).append(rhs);
  35.         return result;
  36.     }
  37.     using SizeType = AdsData::SizeType;
  38.  
  39.     inline bool icmp_less(std::string_view lhs, std::string_view rhs)
  40.     {
  41.         return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](auto x, auto y) {
  42.             return x == '\0'
  43.                        ? y != '\0'
  44.                        : y == '\0' ? false : x == '.' ? y != '.' : y == '.' ? false : std::tolower(x) < std::tolower(y);
  45.         });
  46.     }
  47.     inline bool icmp_equal(std::string_view lhs, std::string_view rhs)
  48.     {
  49.         return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
  50.                           [](auto x, auto y) { return std::tolower(x) == std::tolower(y); });
  51.     }
  52.  
  53.     using adsDataCursor::AdsDataCursor;
  54.     using adsDataCursor::AdsTypeTag;
  55.     using adsDataCursor::DatatypeId;
  56.     using adsDataCursor::IdList;
  57.     using adsDataCursor::implicit_cast;
  58.     using adsDataCursor::LimitMode;
  59.  
  60.     template <LimitMode limitMode = LimitMode::byCount>
  61.     using DtCursor = AdsDataCursor<AdsTypeTag::datatypeEntry, limitMode, limitMode == LimitMode::bySize>;
  62.     template <LimitMode limitMode = LimitMode::byCount>
  63.     using SymCursor       = AdsDataCursor<AdsTypeTag::symbolEntry, limitMode, limitMode == LimitMode::bySize>;
  64.     using ArrayInfoCursor = AdsDataCursor<AdsTypeTag::datatypeArrayInfo, LimitMode::byCount, false>;
  65.  
  66.     using DtIds  = IdList<AdsTypeTag::datatypeEntry>;
  67.     using SymIds = IdList<AdsTypeTag::symbolEntry>;
  68.     using ArrIds = IdList<AdsTypeTag::datatypeArrayInfo>;
  69. } // namespace
  70.  
  71. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  72. class AdsData::SubSymbolInfo
  73. {
  74. public:
  75.     SubSymbolInfo(std::string_view name, SizeType offset, bool isStatic, bool isBit,
  76.                   AdsData::DatatypeInfo* typeData = nullptr)
  77.         : name(name), offset(offset), isStatic(isStatic), isBit(isBit), typeData(typeData)
  78.     {}
  79.     std::string            name;
  80.     SizeType               offset;
  81.     bool                   isStatic;
  82.     bool                   isBit;
  83.     AdsData::DatatypeInfo* typeData;
  84.  
  85.     friend bool operator==(const SubSymbolInfo& lhs, const SubSymbolInfo& rhs)
  86.     {
  87.         return icmp_equal(lhs.name, rhs.name);
  88.     }
  89.     friend bool operator==(const SubSymbolInfo& lhs, std::string_view rhs) { return icmp_equal(lhs.name, rhs); }
  90.     friend bool operator==(std::string_view lhs, const SubSymbolInfo& rhs) { return icmp_equal(lhs, rhs.name); }
  91. };
  92.  
  93. class AdsData::SymbolInfo
  94. {
  95. public:
  96.     SubSymbolInfo baseInfo;
  97.     SizeType      group;
  98.  
  99.     SymbolInfo(const SymCursor<>& sym, DatatypeInfo* typeData)
  100.         : baseInfo(sym.get<SymIds::name>(), sym.get<SymIds::offset>(), sym.get<SymIds::isStatic>(),
  101.                    sym.get<SymIds::isBitValue>(), typeData),
  102.           group(sym.get<SymIds::group>())
  103.     {}
  104.  
  105.     friend bool operator<(const SymbolInfo& lhs, const SymbolInfo& rhs)
  106.     {
  107.         return icmp_less(lhs.baseInfo.name, rhs.baseInfo.name);
  108.     }
  109.     friend bool operator<(const SymbolInfo& lhs, std::string_view rhs) { return icmp_less(lhs.baseInfo.name, rhs); }
  110.     friend bool operator<(std::string_view lhs, const SymbolInfo& rhs) { return icmp_less(lhs, rhs.baseInfo.name); }
  111. };
  112.  
  113. class AdsData::ArrayInfo : public SubSymbolInfo
  114. {
  115. public:
  116.     struct AdsDatatypeArrayInfo
  117.     {
  118.         constexpr AdsDatatypeArrayInfo(std::uint32_t lBound, std::uint32_t elements)
  119.             : lBound(lBound), elements(elements)
  120.         {}
  121.         constexpr AdsDatatypeArrayInfo(const ArrayInfoCursor& cursor)
  122.             : AdsDatatypeArrayInfo(cursor.get<ArrIds::lBound>(), cursor.get<ArrIds::elements>())
  123.         {}
  124.         std::uint32_t lBound;
  125.         std::uint32_t elements;
  126.     };
  127.  
  128.     explicit ArrayInfo(std::vector<AdsDatatypeArrayInfo>&& data, std::string_view name)
  129.         : AdsData::SubSymbolInfo(name, 0, false, false), arrayInfoData_(std::move(data)), numElements_{1}
  130.     {
  131.         for (auto& info : arrayInfoData_)
  132.         {
  133.             SizeType rBound = info.lBound + info.elements - 1;
  134.             ADSDATACURSOR_VERIFY("%1%\narray info corrupted with\ninfo.elements == %2%\ninfo.lBound == %3%\nrBound == "
  135.                                  "%4%",
  136.                                  info.elements != 0 && rBound >= info.lBound, info.elements, info.lBound, rBound);
  137.             ADSDATACURSOR_VERIFY("%1%", std::numeric_limits<SizeType>::max() / info.elements >= numElements_);
  138.             numElements_ *= info.elements;
  139.         }
  140.     }
  141.     ArrayInfo(const DtCursor<>& dt, std::string_view name)
  142.         : ArrayInfo(std::vector<AdsDatatypeArrayInfo>(dt.get<DtIds::arrayInfoData>().begin(),
  143.                                                       dt.get<DtIds::arrayInfoData>().end()),
  144.                     name)
  145.     {}
  146.  
  147.     SizeType index(std::string_view i) const
  148.     {
  149.         auto     workIndex = i;
  150.         SizeType realIndex = 0;
  151.         for (auto& info : arrayInfoData_)
  152.         {
  153.             auto pos = workIndex.find(',');
  154.             if ((&info == &arrayInfoData_.back()) != (pos == workIndex.npos))
  155.                 throw std::out_of_range("index with wrong number of dimensions: "s + i);
  156.             auto curIndex = workIndex;
  157.             if (pos != workIndex.npos)
  158.             {
  159.                 curIndex.remove_suffix(curIndex.size() - pos);
  160.                 workIndex.remove_prefix(pos + 1);
  161.             }
  162.             auto n = svtoi(curIndex);
  163.             if (n < info.lBound || n - info.lBound >= info.elements)
  164.                 throw std::out_of_range("index out of range: "s + i);
  165.             // we don't need to check for overflow here since the constructor already ensures that
  166.             // indizes stay within proper bounds
  167.             realIndex = realIndex * info.elements + (n - info.lBound);
  168.         }
  169.         return realIndex;
  170.     }
  171.     std::string toString(SizeType i) const
  172.     {
  173.         if (i >= numElements_)
  174.             throw std::out_of_range("index out of range");
  175.         std::string result = "]";
  176.         for (auto it = arrayInfoData_.cend(); it != arrayInfoData_.cbegin();)
  177.         {
  178.             auto& info     = *--it;
  179.             auto  curIndex = i % info.elements + info.lBound;
  180.             i /= info.elements;
  181.             do
  182.             {
  183.                 result.push_back(static_cast<char>('0' + curIndex % 10));
  184.             } while (curIndex /= 10);
  185.             if (&info != &arrayInfoData_.front())
  186.                 result.push_back(',');
  187.         }
  188.         result.push_back('[');
  189.         std::reverse(result.begin(), result.end());
  190.         return result;
  191.     }
  192.     SizeType        elemSize() const noexcept;
  193.     SizeType        numElements() const noexcept { return numElements_; }
  194.     static SizeType svtoi(std::string_view s)
  195.     {
  196.         SizeType result = 0;
  197.         if (s.empty())
  198.             throw std::out_of_range("index corrupted");
  199.         for (; !s.empty(); s.remove_prefix(1))
  200.         {
  201.             if (s[0] < '0' || s[0] > '9')
  202.                 throw std::out_of_range("index corrupted");
  203.             auto curDigit = static_cast<unsigned char>(s[0] - '0');
  204.             if ((std::numeric_limits<SizeType>::max() - curDigit) / 10 < result)
  205.                 throw std::out_of_range("index corrupted");
  206.             result = result * 10 + curDigit;
  207.         }
  208.         return result;
  209.     }
  210.  
  211. private:
  212.     std::vector<AdsDatatypeArrayInfo> arrayInfoData_;
  213.     SizeType                          numElements_;
  214. };
  215.  
  216. class AdsData::DatatypeInfo
  217. {
  218.     static constexpr auto ptrStr = "POINTER TO "sv;
  219.     static constexpr auto refStr = "REFERENCE TO "sv;
  220.     static constexpr auto arrStr = "ARRAY ["sv;
  221.  
  222. public:
  223.     struct Category
  224.     {
  225.         enum : std::size_t
  226.         {
  227.             base,
  228.             alias,
  229.             pointer,
  230.             reference,
  231.             array,
  232.             class_ // class_ = struct, union, function block
  233.         };
  234.     };
  235.     using SpecType = std::variant<std::monostate,
  236.                                   DatatypeInfo*, // alias
  237.                                   SubSymbolInfo, // pointer
  238.                                   SubSymbolInfo, // reference
  239.                                   ArrayInfo,     // array
  240.                                   std::vector<SubSymbolInfo>>;
  241.  
  242.     DatatypeInfo(std::in_place_index_t<Category::base>, std::string_view name, SizeType size, DatatypeId id)
  243.         : name(name), size(size), id(id), typeSpecs(std::in_place_index_t<Category::base>{})
  244.     {}
  245.  
  246.     DatatypeInfo(std::in_place_index_t<Category::pointer>, std::string_view name, SizeType size, DatatypeId id)
  247.         : name(name), size(size), id(id)
  248.     {
  249.         typeSpecs.emplace<Category::pointer>(name.substr(ptrStr.size()), 0, false, false);
  250.     }
  251.  
  252.     DatatypeInfo(std::in_place_index_t<Category::reference>, std::string_view name, SizeType size, DatatypeId id)
  253.         : name(name), size(size), id(id)
  254.     {
  255.         typeSpecs.emplace<Category::reference>(name.substr(ptrStr.size()), 0, false, false);
  256.     }
  257.  
  258.     DatatypeInfo(std::in_place_index_t<Category::array>, std::string_view name, SizeType size, DatatypeId id)
  259.         : name(name), size(size), id(id)
  260.     {
  261.         auto                                         elemName = name.substr(name.find(" OF "sv) + " OF "sv.size());
  262.         auto                                         index = name.substr(arrStr.size(), name.find(']') - arrStr.size());
  263.         std::vector<ArrayInfo::AdsDatatypeArrayInfo> dims;
  264.         while (!index.empty())
  265.         {
  266.             static constexpr auto svtoi = [](std::string_view& i) {
  267.                 SizeType result = 0;
  268.                 for (; !i.empty() && i[0] >= '0' && i[0] <= '9'; i.remove_prefix(1))
  269.                 {
  270.                     auto curDigit = static_cast<unsigned char>(i[0] - '0');
  271.                     result        = result * 10 + curDigit;
  272.                 }
  273.                 return result;
  274.             };
  275.             SizeType lBound = svtoi(index);
  276.             index.remove_prefix(2); // ..
  277.             SizeType rBound = svtoi(index);
  278.             dims.emplace_back(lBound, rBound - lBound + 1);
  279.             if (!index.empty())
  280.                 index.remove_prefix(1); // ,
  281.         }
  282.         typeSpecs.emplace<Category::array>(std::move(dims), elemName);
  283.     }
  284.  
  285.     explicit DatatypeInfo(const DtCursor<>& dt)
  286.         : name(dt.get<DtIds::name>()), size(dt.get<DtIds::size>()), id(dt.get<DtIds::typeId>())
  287.     {
  288.         ADSDATACURSOR_VERIFY("%1%\nEntry must be either datatype or dataitem",
  289.                              dt.get<DtIds::isDatatype>() != dt.get<DtIds::isDataitem>());
  290.         ADSDATACURSOR_VERIFY("%1%\ndatatype cannot be both array and struct/union at the same time",
  291.                              !dt.get<DtIds::isDatatype>()
  292.                                  || (dt.get<DtIds::numArrayDims>() == 0 || dt.get<DtIds::numSubItems>() == 0));
  293.         ADSDATACURSOR_VERIFY("%1%\ndataitem cannot contain subelements",
  294.                              !dt.get<DtIds::isDataitem>()
  295.                                  || (dt.get<DtIds::numArrayDims>() == 0 && dt.get<DtIds::numSubItems>() == 0));
  296.  
  297.         if (name.compare(0, ptrStr.size(), ptrStr) == 0)
  298.         {
  299.             typeSpecs.emplace<Category::pointer>(name.substr(ptrStr.size()), 0, false, false);
  300.             size = 0;
  301.             id   = DatatypeId::blob_;
  302.         }
  303.         else if (name.compare(0, refStr.size(), refStr) == 0)
  304.         {
  305.             typeSpecs.emplace<Category::reference>(name.substr(refStr.size()), 0, false, false);
  306.             size = 0;
  307.             id   = DatatypeId::blob_;
  308.         }
  309.         else if (dt.get<DtIds::numSubItems>() != 0) // struct/union/FB
  310.         {
  311.             auto& subs = typeSpecs.emplace<Category::class_>();
  312.             subs.reserve(dt.get<DtIds::numSubItems>());
  313.             for (auto sub = dt.get<DtIds::subItemData>(); sub; ++sub)
  314.             {
  315.                 ADSDATACURSOR_VERIFY("%1%\nsubElements must be dataitems", sub.get<DtIds::isDataitem>());
  316.                 subs.emplace_back(sub.get<DtIds::name>(), sub.get<DtIds::offset>(), sub.get<DtIds::isStatic>(),
  317.                                   sub.get<DtIds::isBitValue>(), nullptr);
  318.             }
  319.         }
  320.         else if (dt.get<DtIds::numArrayDims>() != 0)
  321.         {
  322.             ADSDATACURSOR_VERIFY("%1%", name.compare(0, arrStr.size(), arrStr) == 0);
  323.             typeSpecs.emplace<Category::array>(dt, name.substr(name.find(" OF "sv) + " OF "sv.size()));
  324.             size = 0;
  325.             id   = DatatypeId::blob_;
  326.         }
  327.         else if (!dt.get<DtIds::type>().empty())
  328.             typeSpecs.emplace<Category::alias>();
  329.         else
  330.             typeSpecs.emplace<Category::base>();
  331.     }
  332.  
  333.     DatatypeInfo(std::in_place_index_t<Category::array>, const DtCursor<>& dt, std::string_view name)
  334.         : name(name), size(0), id(DatatypeId::blob_)
  335.     {
  336.         ADSDATACURSOR_VERIFY("%1%", dt.get<DtIds::numArrayDims>() != 0);
  337.         typeSpecs.emplace<Category::array>(dt, name.substr(name.find(" OF "sv) + " OF "sv.size()));
  338.         size = 0;
  339.         id   = DatatypeId::blob_;
  340.     }
  341.  
  342.     std::string name;
  343.     SizeType    size;
  344.     DatatypeId  id;
  345.     bool        visited = false; // used for cycle detection
  346.     SpecType    typeSpecs;
  347.  
  348.     friend bool operator<(const AdsData::DatatypeInfo& lhs, const AdsData::DatatypeInfo& rhs)
  349.     {
  350.         return lhs.name < rhs.name;
  351.     }
  352.     friend bool operator<(const AdsData::DatatypeInfo& lhs, std::string_view rhs) { return lhs.name < rhs; }
  353.     friend bool operator<(std::string_view lhs, const AdsData::DatatypeInfo& rhs) { return lhs == rhs.name; }
  354.     friend bool operator==(const AdsData::DatatypeInfo& lhs, const AdsData::DatatypeInfo& rhs)
  355.     {
  356.         return lhs.name == rhs.name;
  357.     }
  358.     friend bool operator==(const AdsData::DatatypeInfo& lhs, std::string_view rhs) { return lhs.name < rhs; }
  359.     friend bool operator==(std::string_view lhs, const AdsData::DatatypeInfo& rhs) { return lhs == rhs.name; }
  360. };
  361.  
  362. SizeType AdsData::ArrayInfo::elemSize() const noexcept { return typeData->size; }
  363.  
  364. namespace
  365. {
  366.     // check for cycles and fix array size while we're at it
  367.     SizeType cycleCheck(AdsData::DatatypeInfo* p)
  368.     {
  369.         using Category = AdsData::DatatypeInfo::Category;
  370.         ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: cycle detected", !p->visited);
  371.         p->visited                                                        = true;
  372.         static constexpr auto                                     deleter = [](auto* x) { x->visited = false; };
  373.         std::unique_ptr<AdsData::DatatypeInfo, decltype(deleter)> guard(p, deleter);
  374.         switch (p->typeSpecs.index())
  375.         {
  376.             default:
  377.                 assert(false);
  378.             case Category::base:
  379.             case Category::pointer:
  380.             case Category::reference:
  381.                 break;
  382.             case Category::alias:
  383.                 cycleCheck(std::get<Category::alias>(p->typeSpecs));
  384.                 break;
  385.             case Category::array:
  386.                 if (p->size == 0)
  387.                 {
  388.                     auto& info     = std::get<Category::array>(p->typeSpecs);
  389.                     auto  elemSize = cycleCheck(info.typeData);
  390.                     ADSDATACURSOR_VERIFY("%1%", std::numeric_limits<SizeType>::max() / elemSize >= info.numElements())
  391.                     p->size = elemSize * info.numElements();
  392.                 }
  393.                 break;
  394.             case Category::class_:
  395.                 for (auto& sub : std::get<Category::class_>(p->typeSpecs))
  396.                     cycleCheck(sub.typeData);
  397.                 break;
  398.         }
  399.         ADSDATACURSOR_VERIFY("%1%", p->size != 0);
  400.         return p->size;
  401.     }
  402.  
  403.     const AdsData::DatatypeInfo* followAlias(const AdsData::DatatypeInfo* p) noexcept
  404.     {
  405.         while (auto q = std::get_if<AdsData::DatatypeInfo::Category::alias>(&p->typeSpecs))
  406.             p = *q;
  407.         return p;
  408.     }
  409. } // namespace
  410.  
  411. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  412. AdsData::AdsData() noexcept          = default;
  413. AdsData::AdsData(AdsData&&) noexcept = default;
  414. AdsData& AdsData::operator=(AdsData&&) noexcept = default;
  415.  
  416. AdsData::~AdsData() noexcept = default;
  417.  
  418. AdsData::AdsData(const std::vector<char>& symData, const std::vector<char>& dtData) : symbols_{}, types_{}
  419. {
  420.     using Category = DatatypeInfo::Category;
  421.  
  422.     // count how many datatype entries we have and verify their integrity
  423.     DtCursor<> allDts(&dtData[0], DtCursor<LimitMode::bySize>(&dtData[0], dtData.size()).size());
  424.  
  425.     // add to types_
  426.     types_.reserve(allDts.count());
  427.     for (auto& dt : allDts)
  428.         types_.emplace_back(dt);
  429.     std::sort(types_.begin(), types_.end());
  430.  
  431.     // TwinCAT2 doesn't send info about basic datatypes so we add them here as needed
  432.     // we don't link them yet, because adding to the types-vector might cause a reallocation,
  433.     // invalidating references in the process
  434.     static constexpr std::tuple<std::string_view, SizeType, DatatypeId> defaultTypes[] = {
  435.         {"BOOL"sv, 1, DatatypeId::bool_},     {"BYTE"sv, 1, DatatypeId::uint8_},   {"DATE"sv, 4, DatatypeId::blob_},
  436.         {"DINT"sv, 4, DatatypeId::int32_},    {"DT"sv, 4, DatatypeId::blob_},      {"DWORD"sv, 4, DatatypeId::uint32_},
  437.         {"INT"sv, 2, DatatypeId::int16_},     {"INT16"sv, 2, DatatypeId::int16_},  {"LREAL"sv, 8, DatatypeId::double_},
  438.         {"REAL"sv, 4, DatatypeId::float_},    {"SINT"sv, 1, DatatypeId::int8_},    {"TIME"sv, 4, DatatypeId::blob_},
  439.         {"TOD"sv, 4, DatatypeId::blob_},      {"UDINT"sv, 4, DatatypeId::uint32_}, {"UINT"sv, 2, DatatypeId::uint16_},
  440.         {"UINT16"sv, 2, DatatypeId::uint16_}, {"USINT"sv, 1, DatatypeId::uint8_},  {"WORD"sv, 2, DatatypeId::uint16_}};
  441.     for (auto& defaultType : defaultTypes)
  442.     {
  443.         auto name = std::get<0>(defaultType);
  444.         auto it   = std::lower_bound(types_.begin(), types_.end(), name);
  445.         if (it == types_.end() || it->name != name)
  446.             types_.emplace(it, std::in_place_index_t<Category::base>{}, name, std::get<1>(defaultType),
  447.                            std::get<2>(defaultType));
  448.     }
  449.  
  450.     //  add missing types due to TwinCAT3's POINTER/ARRAY bug
  451.     auto addMissingType = [&](decltype(types_)::iterator it, std::string_view name) {
  452.         for (;;)
  453.         {
  454.             static constexpr auto ptrStr = "POINTER TO "sv;
  455.             static constexpr auto refStr = "REFERENCE TO "sv;
  456.             static constexpr auto arrStr = "ARRAY ["sv;
  457.             if (name.compare(0, ptrStr.size(), ptrStr) == 0)
  458.             {
  459.                 types_.emplace(it, std::in_place_index_t<Category::pointer>{}, name, 0, DatatypeId::blob_);
  460.                 name.remove_prefix(ptrStr.size());
  461.             }
  462.             else if (name.compare(0, refStr.size(), refStr) == 0)
  463.             {
  464.                 types_.emplace(it, std::in_place_index_t<Category::reference>{}, name, 0, DatatypeId::blob_);
  465.                 name.remove_prefix(refStr.size());
  466.             }
  467.             else if (name.compare(0, arrStr.size(), arrStr) == 0)
  468.             {
  469.                 types_.emplace(it, std::in_place_index_t<Category::array>{}, name, 0, DatatypeId::blob_);
  470.                 name.remove_prefix(name.find(" OF "sv) + " OF "sv.size());
  471.             }
  472.             else
  473.             {
  474.                 // add missing types for TwinCAT2
  475.                 auto pos = name.find('(');
  476.                 if (pos == 0) // default to int16_
  477.                     types_.emplace(it, std::in_place_index_t<Category::base>{}, name, 2, DatatypeId::blob_);
  478.                 else if (pos != name.npos) // subrange
  479.                 {
  480.                     auto baseName = name.substr(0, name.find('('));
  481.                     if (baseName == "STRING"sv)
  482.                     {
  483.                         SizeType strLen = 0;
  484.                         for (; name[++pos] != ')';)
  485.                         {
  486.                             auto curDigit = static_cast<unsigned char>(name[pos] - '0');
  487.                             strLen        = strLen * 10 + curDigit;
  488.                         }
  489.                         types_.emplace(it, std::in_place_index_t<Category::base>{}, name, strLen + 1,
  490.                                        DatatypeId::string_);
  491.                     }
  492.                     else
  493.                     {
  494.                         auto baseIt = std::lower_bound(types_.begin(), types_.end(), baseName);
  495.                         ADSDATACURSOR_VERIFY("%1%", baseIt != types_.end() && baseName == baseIt->name);
  496.                         types_.emplace(it, std::in_place_index_t<Category::base>{}, name, baseIt->size, baseIt->id);
  497.                     }
  498.                 }
  499.                 break;
  500.             }
  501.             it = std::lower_bound(types_.begin(), types_.end(), name);
  502.             if (it != types_.end() && it->name == name)
  503.                 break;
  504.         }
  505.     };
  506.     // count how many symbol entries we have and verify their integrity
  507.     SymCursor<> allSyms(&symData[0], SymCursor<LimitMode::bySize>(&symData[0], symData.size()).size());
  508.  
  509.     // add missing types as needed
  510.     for (auto& sym : allSyms)
  511.     {
  512.         ADSDATACURSOR_VERIFY("%1%\nsymbols must have a type", !sym.get<SymIds::type>().empty());
  513.         auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
  514.         if (it == types_.end() || it->name != sym.get<SymIds::type>())
  515.         {
  516.             addMissingType(it, sym.get<SymIds::type>());
  517.         }
  518.     }
  519.  
  520.     for (auto& dt : allDts)
  521.     {
  522.         for (auto& sub : dt.get<DtIds::subItemData>())
  523.         {
  524.             ADSDATACURSOR_VERIFY("%1%\nstructure elements must have a type", !sub.get<DtIds::type>().empty());
  525.             auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
  526.             if (it == types_.end() || it->name != sub.get<DtIds::type>())
  527.                 addMissingType(it, sub.get<DtIds::type>());
  528.         }
  529.         auto type = dt.get<DtIds::type>();
  530.         if (type.empty())
  531.             continue; // base type or structure
  532.     }
  533.  
  534.     for (auto typeIt = types_.begin(); typeIt != types_.end();)
  535.     {
  536.         if (!typeIt->visited)
  537.         {
  538.             typeIt->visited = true;
  539.             switch (typeIt->typeSpecs.index())
  540.             {
  541.                 default:
  542.                     assert(false);
  543.                 case Category::base:
  544.                 case Category::alias:
  545.                 case Category::class_:
  546.                     break;
  547.                 case Category::pointer:
  548.                 case Category::reference:
  549.                 case Category::array:
  550.                 {
  551.                     std::string_view name = typeIt->typeSpecs.index() == Category::pointer
  552.                                                 ? std::get<Category::pointer>(typeIt->typeSpecs).name
  553.                                                 : typeIt->typeSpecs.index() == Category::reference
  554.                                                       ? std::get<Category::reference>(typeIt->typeSpecs).name
  555.                                                       : std::get<Category::array>(typeIt->typeSpecs).name;
  556.                     auto it = std::lower_bound(types_.begin(), types_.end(), name);
  557.                     if (it == types_.end() || it->name != name)
  558.                     {
  559.                         addMissingType(it, name);
  560.                         typeIt = types_.begin();
  561.                         continue;
  562.                     }
  563.                 }
  564.             }
  565.         }
  566.         ++typeIt;
  567.     }
  568.  
  569.     auto     pvoidIt     = std::lower_bound(types_.begin(), types_.end(), "PVOID"sv);
  570.     SizeType pointerSize = pvoidIt == types_.end() || pvoidIt->name != "PVOID"sv ? 4 : pvoidIt->size;
  571.  
  572.     // crosslink datatypes
  573.     for (auto& dt : allDts)
  574.     {
  575.         auto type = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::name>());
  576.         switch (type->typeSpecs.index())
  577.         {
  578.             default:
  579.                 assert(false);
  580.             case Category::base:
  581.             case Category::pointer:
  582.             case Category::reference:
  583.             case Category::array:
  584.                 break;
  585.             case Category::alias:
  586.             {
  587.                 auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
  588.                 std::get<Category::alias>(type->typeSpecs) = &*it;
  589.                 ADSDATACURSOR_VERIFY("%1%", dt.get<DtIds::size>() == it->size);
  590.                 break;
  591.             }
  592.             case Category::class_:
  593.             {
  594.                 auto sub = dt.get<DtIds::subItemData>();
  595.                 for (auto& info : std::get<Category::class_>(type->typeSpecs))
  596.                 {
  597.                     auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
  598.                     ADSDATACURSOR_VERIFY(
  599.                         "%1%\nDatatypes corrupted: mismatched size\nit->size == %2%\nsub.get<DtIds::size>() == %3%",
  600.                         it->size == 0 || sub.get<DtIds::size>() == it->size, it->size, sub.get<DtIds::size>());
  601.                     info.typeData = &*it;
  602.                     ++sub;
  603.                 }
  604.                 break;
  605.             }
  606.         }
  607.     }
  608.     // link other types
  609.     for (auto& type : types_)
  610.     {
  611.         type.visited = false;
  612.         switch (type.typeSpecs.index())
  613.         {
  614.             default:
  615.                 assert(false);
  616.             case Category::base:
  617.             case Category::alias:
  618.             case Category::class_:
  619.                 continue;
  620.             case Category::pointer:
  621.             case Category::reference:
  622.             {
  623.                 auto& info = type.typeSpecs.index() == Category::pointer
  624.                                  ? std::get<Category::pointer>(type.typeSpecs)
  625.                                  : std::get<Category::reference>(type.typeSpecs);
  626.                 auto it = std::lower_bound(types_.begin(), types_.end(), info.name);
  627.                 ADSDATACURSOR_VERIFY("%1%", it != types_.end() && it->name == info.name);
  628.                 info.typeData = &*it;
  629.                 type.size     = pointerSize;
  630.                 info.name     = "^"sv;
  631.                 continue;
  632.             }
  633.             case Category::array:
  634.             {
  635.                 auto& info = std::get<Category::array>(type.typeSpecs);
  636.                 auto  it   = std::lower_bound(types_.begin(), types_.end(), info.name);
  637.                 ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched element size\ntype->size == %2%\nit->size "
  638.                                      "== %3%\ninfo.numElements() == %4%",
  639.                                      type.size == 0 || it->size == 0 || type.size / info.numElements() == it->size,
  640.                                      type.size, it->size, info.numElements());
  641.                 info.typeData = &*it;
  642.                 info.name     = ""sv;
  643.             }
  644.         }
  645.     }
  646.     // make sure we didn't create a cycle, which should never happen,
  647.     // an alias cannot refer to itself and a structure cannot contain itself
  648.     // also fix array size
  649.     for (auto& info : types_)
  650.         cycleCheck(&info);
  651.  
  652.     symbols_.reserve(allSyms.count());
  653.     for (auto& sym : allSyms)
  654.     {
  655.         auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
  656.         ADSDATACURSOR_VERIFY(
  657.             "%1%\nSymboldata corrupted: mismatched size\nit->size == %2%\nsym.get<SymIds::size>() == %3%",
  658.             sym.get<SymIds::size>() == it->size, it->size, sym.get<SymIds::size>());
  659.         symbols_.emplace_back(sym, &*it);
  660.     }
  661.     std::sort(symbols_.begin(), symbols_.end());
  662.  
  663.     // the offset of static vars in function blocks is not given in the datatype info and must therefore be derived from
  664.     // the main symbol
  665.     for (auto& type : types_)
  666.     {
  667.         if (type.typeSpecs.index() != Category::class_)
  668.             continue;
  669.         for (auto& sub : std::get<Category::class_>(type.typeSpecs))
  670.         {
  671.             if (!sub.isStatic)
  672.                 continue;
  673.             auto mainSymbol = type.name + '.' + sub.name;
  674.             auto sym        = std::lower_bound(symbols_.begin(), symbols_.end(), mainSymbol);
  675.             ADSDATACURSOR_VERIFY("%1%\nmain symbol for static var %2% not found",
  676.                                  (sym != symbols_.end() && mainSymbol == sym->baseInfo.name), mainSymbol);
  677.             // fix offset
  678.             sub.offset = sym->baseInfo.offset;
  679.         }
  680.     }
  681. }
  682.  
  683. AdsVarData AdsData::maybe(std::string_view name) const
  684. {
  685.     auto curName = name;
  686.     if (auto pos = curName.find('['); pos != curName.npos)
  687.         curName.remove_suffix(curName.size() - pos);
  688.     auto sym = std::upper_bound(symbols_.begin(), symbols_.end(), curName);
  689.     if (sym == symbols_.begin()
  690.         || ((void)--sym, curName.compare(0, sym->baseInfo.name.size(), sym->baseInfo.name) != 0))
  691.         return {};
  692.     AdsVarData data{&sym->baseInfo, sym->group, sym->baseInfo.offset};
  693.     if (name.size() == sym->baseInfo.name.size())
  694.         return data;
  695.     else
  696.         return data.maybe(
  697.             std::string_view{name.data() + sym->baseInfo.name.size(), name.size() - sym->baseInfo.name.size()});
  698. }
  699. AdsVarData AdsData::operator[](std::string_view name) const
  700. {
  701.     if (auto data = maybe(name))
  702.         return data;
  703.     else
  704.         throw std::out_of_range("symbol "sv + name + " not found"sv);
  705. }
  706.  
  707. AdsData::iterator AdsData::begin() const noexcept { return iterator{symbols_.begin()}; }
  708. AdsData::iterator AdsData::end() const noexcept { return iterator{symbols_.end()}; }
  709. AdsData::iterator AdsData::cbegin() const noexcept { return begin(); }
  710. AdsData::iterator AdsData::cend() const noexcept { return end(); }
  711. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  712. std::string AdsVarData::name(std::string prefix) const
  713. {
  714.     if (!info_->name.empty())
  715.     {
  716.         prefix.reserve(prefix.size() + 1 + info_->name.size());
  717.         if (!prefix.empty() && info_->name != "^"sv)
  718.             prefix += '.';
  719.         prefix += info_->name;
  720.         return prefix;
  721.     }
  722.     else
  723.         return std::move(prefix) + shortName();
  724. }
  725. std::string AdsVarData::shortName() const
  726. {
  727.     return info_->name.empty() ? static_cast<const AdsData::ArrayInfo*>(info_)->toString(index_) : info_->name;
  728. }
  729. const std::string& AdsVarData::type() const noexcept { return info_->typeData->name; }
  730. DatatypeId         AdsVarData::typeId() const noexcept { return info_->typeData->id; }
  731. SizeType           AdsVarData::group() const noexcept { return group_; }
  732. SizeType           AdsVarData::offset() const noexcept { return offset_; }
  733. SizeType           AdsVarData::size() const noexcept { return info_->typeData->size; }
  734.  
  735. bool AdsVarData::isPointer() const noexcept
  736. {
  737.     return followAlias(info_->typeData)->typeSpecs.index() == AdsData::DatatypeInfo::Category::pointer;
  738. }
  739. bool AdsVarData::isReference() const noexcept
  740. {
  741.     return followAlias(info_->typeData)->typeSpecs.index() == AdsData::DatatypeInfo::Category::reference;
  742. }
  743.  
  744. bool AdsVarData::isStatic() const noexcept { return info_->isStatic; }
  745.  
  746. bool AdsVarData::empty() const noexcept { return subElements() == 0; }
  747.  
  748. SizeType AdsVarData::subElements() const noexcept
  749. {
  750.     using Category = AdsData::DatatypeInfo::Category;
  751.     auto real_type = followAlias(info_->typeData);
  752.     switch (real_type->typeSpecs.index())
  753.     {
  754.         default:
  755.         case Category::alias:
  756.             assert(false);
  757.         case Category::base:
  758.         case Category::pointer:
  759.         case Category::reference:
  760.             return 0;
  761.         case Category::array:
  762.             return std::get<Category::array>(real_type->typeSpecs).numElements();
  763.         case Category::class_:
  764.             return static_cast<SizeType>(std::get<Category::class_>(real_type->typeSpecs).size());
  765.     }
  766. }
  767.  
  768. AdsVarData AdsVarData::deref(SizeType address) const
  769. {
  770.     ADSDATACURSOR_VERIFY("%1%", isPointer() || isReference());
  771.     using Category = AdsData::DatatypeInfo::Category;
  772.     auto  dt       = followAlias(info_->typeData);
  773.     auto& info     = dt->typeSpecs.index() == Category::pointer ? std::get<Category::pointer>(dt->typeSpecs)
  774.                                                             : std::get<Category::reference>(dt->typeSpecs);
  775.     return {&info, group(), address};
  776. }
  777.  
  778. AdsVarData AdsVarData::maybe(std::string_view name) const
  779. {
  780.     using Category = AdsData::DatatypeInfo::Category;
  781.     auto dt        = followAlias(info_->typeData);
  782.     if (name[0] == '.' && dt->typeSpecs.index() == Category::class_)
  783.     {
  784.         name.remove_prefix(1);
  785.         auto shortName = name;
  786.         auto pos       = name.find_first_of(".["sv);
  787.         if (pos != name.npos)
  788.             shortName.remove_suffix(shortName.size() - pos);
  789.         auto& subs = std::get<Category::class_>(dt->typeSpecs);
  790.         auto  sub  = std::find_if(subs.begin(), subs.end(), [=](auto& v) { return icmp_equal(shortName, v.name); });
  791.         if (sub == subs.end())
  792.             return {};
  793.         AdsVarData subData{&*sub, group(), sub->isStatic ? offset() + sub->offset : sub->offset};
  794.         if (pos == name.npos)
  795.             return subData;
  796.         name.remove_prefix(pos);
  797.         return subData.maybe(name);
  798.     }
  799.     else if (name[0] == '[' && dt->typeSpecs.index() == Category::array)
  800.     {
  801.         name.remove_prefix(1);
  802.         auto pos = name.find(']');
  803.         if (pos == name.npos)
  804.             return {};
  805.         auto index = name;
  806.         index.remove_suffix(index.size() - pos);
  807.         auto& info = std::get<Category::array>(dt->typeSpecs);
  808.         try
  809.         {
  810.             auto i = info.index(index);
  811.             name.remove_prefix(pos + 1); // "index]"
  812.             AdsVarData subData{&info, group(), offset() + info.elemSize() * i, i};
  813.             if (name.empty())
  814.                 return subData;
  815.             else
  816.                 return subData.maybe(name);
  817.         }
  818.         catch (std::out_of_range&)
  819.         {
  820.             return {};
  821.         }
  822.     }
  823.     else
  824.         return {};
  825. }
  826.  
  827. AdsVarData AdsVarData::operator[](std::string_view name) const
  828. {
  829.     if (auto data = maybe(name))
  830.         return data;
  831.     else
  832.         throw std::out_of_range("subsymbol "sv + name + " not found in "sv + shortName());
  833. }
  834.  
  835. AdsVarData::iterator AdsVarData::begin() const noexcept
  836. {
  837.     using Category = AdsData::DatatypeInfo::Category;
  838.     auto real_type = followAlias(info_->typeData);
  839.     switch (real_type->typeSpecs.index())
  840.     {
  841.         default:
  842.         case Category::alias:
  843.             assert(false);
  844.         case Category::base:
  845.         case Category::pointer:
  846.         case Category::reference:
  847.             return iterator{nullptr, 0, 0, 0};
  848.         case Category::array:
  849.         {
  850.             auto& info = std::get<Category::array>(real_type->typeSpecs);
  851.             return iterator{&info, group_, offset_, 0};
  852.         }
  853.         case Category::class_:
  854.         {
  855.             auto& info = std::get<Category::class_>(real_type->typeSpecs);
  856.             return iterator{info.empty() ? nullptr : &info.front(), group_, offset_, 0};
  857.         }
  858.     }
  859. }
  860.  
  861. AdsVarData::iterator AdsVarData::end() const noexcept
  862. {
  863.     using Category = AdsData::DatatypeInfo::Category;
  864.     auto real_type = followAlias(info_->typeData);
  865.     switch (real_type->typeSpecs.index())
  866.     {
  867.         default:
  868.         case Category::alias:
  869.             assert(false);
  870.         case Category::base:
  871.         case Category::pointer:
  872.         case Category::reference:
  873.             return iterator{nullptr, 0, 0, 0};
  874.         case Category::array:
  875.         {
  876.             auto& info = std::get<Category::array>(real_type->typeSpecs);
  877.             return iterator{&info, group_, offset_, info.numElements()};
  878.         }
  879.         case Category::class_:
  880.         {
  881.             auto& info = std::get<Category::class_>(real_type->typeSpecs);
  882.             return iterator{info.empty() ? nullptr : &info.back() + 1, group_, offset_, 0};
  883.         }
  884.     }
  885. }
  886.  
  887. AdsVarData::iterator AdsVarData::cbegin() const noexcept { return begin(); }
  888. AdsVarData::iterator AdsVarData::cend() const noexcept { return end(); }
  889.  
  890. bool        AdsVarData::good() const noexcept { return info_; }
  891. AdsVarData::operator bool() const noexcept { return good(); }
  892. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  893. AdsData::iterator::reference AdsData::iterator::operator*() const noexcept
  894. {
  895.     return AdsVarData{&iter_->baseInfo, iter_->group, iter_->baseInfo.offset};
  896. }
  897.  
  898. AdsData::iterator::pointer AdsData::iterator::operator->() const noexcept { return **this; }
  899.  
  900. bool operator==(AdsData::iterator lhs, AdsData::iterator rhs) noexcept { return lhs.iter_ == rhs.iter_; }
  901. bool operator!=(AdsData::iterator lhs, AdsData::iterator rhs) noexcept { return lhs.iter_ != rhs.iter_; }
  902.  
  903. AdsData::iterator& AdsData::iterator::operator++() noexcept
  904. {
  905.     ++iter_;
  906.     return *this;
  907. }
  908.  
  909. AdsData::iterator AdsData::iterator::operator++(int) noexcept
  910. {
  911.     auto tmp = *this;
  912.     ++*this;
  913.     return tmp;
  914. }
  915. AdsData::iterator::iterator(std::vector<AdsData::SymbolInfo>::const_iterator it) noexcept : iter_{it} {}
  916.  
  917. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  918.  
  919. AdsVarData::iterator::reference AdsVarData::iterator::operator*() const noexcept
  920. {
  921.     if (info_->name.empty()) // array-element ?
  922.         return AdsVarData{info_, group_, offset_ + index_ * info_->typeData->size, index_};
  923.     else if (info_->isBit)
  924.         return AdsVarData{info_, group_ + 1, info_->isStatic ? info_->offset : offset_ * 8 + info_->offset};
  925.     else
  926.         return AdsVarData{info_, group_, info_->isStatic ? info_->offset : offset_ + info_->offset};
  927. }
  928.  
  929. AdsVarData::iterator::pointer AdsVarData::iterator::operator->() const noexcept { return **this; }
  930.  
  931. bool operator==(const AdsVarData::iterator& lhs, const AdsVarData::iterator& rhs) noexcept
  932. {
  933.     return lhs.info_ == rhs.info_ && lhs.index_ == rhs.index_ && lhs.offset_ == rhs.offset_ && lhs.group_ == rhs.group_;
  934. }
  935.  
  936. bool operator!=(const AdsVarData::iterator& lhs, const AdsVarData::iterator& rhs) noexcept { return !(lhs == rhs); }
  937.  
  938. AdsVarData::iterator& AdsVarData::iterator::operator++() noexcept
  939. {
  940.     if (info_->name.empty()) // array-element ?
  941.         ++index_;
  942.     else
  943.         ++info_;
  944.     return *this;
  945. }
  946.  
  947. AdsVarData::iterator AdsVarData::iterator::operator++(int) noexcept
  948. {
  949.     auto tmp = *this;
  950.     ++*this;
  951.     return tmp;
  952. }
  953.  
  954. AdsVarData::iterator::iterator(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset,
  955.                                SizeType index) noexcept
  956.     : info_{info}, group_{group}, offset_{offset}, index_{index}
  957. {}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement