LCOV - code coverage report
Current view: top level - stack - Dictionary.cpp (source / functions) Coverage Total Hit
Test: final-coverage.info Lines: 74.2 % 302 224
Test Date: 2025-02-10 18:26:37 Functions: 77.8 % 18 14

            Line data    Source code
       1              : #include <iostream>
       2              : /*
       3              :  ________________________________________________________________________
       4              : |                                                                        |
       5              : |       _ _                      _                         _             |
       6              : |      | (_)                    | |                       | |            |
       7              : |    __| |_  __ _ _ __ ___   ___| |_ ___ _ __ ___ ___   __| | ___  ___   |
       8              : |   / _` | |/ _` | '_ ` _ \ / _ \ __/ _ \ '__/ __/ _ \ / _` |/ _ \/ __|  |
       9              : |  | (_| | | (_| | | | | | |  __/ ||  __/ | | (_| (_) | (_| |  __/ (__   |
      10              : |   \__,_|_|\__,_|_| |_| |_|\___|\__\___|_|  \___\___/ \__,_|\___|\___|  |
      11              : |                                                                        |
      12              : |________________________________________________________________________|
      13              : 
      14              : C++ CODEC FOR DIAMETER PROTOCOL (RFC 6733)
      15              : Version 0.0.z
      16              : https://github.com/testillano/diametercodec
      17              : 
      18              : Licensed under the MIT License <http://opensource.org/licenses/MIT>.
      19              : SPDX-License-Identifier: MIT
      20              : Copyright (c) 2021 Eduardo Ramos
      21              : 
      22              : Permission is hereby  granted, free of charge, to any  person obtaining a copy
      23              : of this software and associated  documentation files (the "Software"), to deal
      24              : in the Software  without restriction, including without  limitation the rights
      25              : to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
      26              : copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
      27              : furnished to do so, subject to the following conditions:
      28              : 
      29              : The above copyright notice and this permission notice shall be included in all
      30              : copies or substantial portions of the Software.
      31              : 
      32              : THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
      33              : IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
      34              : FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
      35              : AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
      36              : LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      37              : OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
      38              : SOFTWARE.
      39              : */
      40              : 
      41              : 
      42              : // Project
      43              : #include <ert/tracing/Logger.hpp>
      44              : #include <ert/diametercodec/stack/Dictionary.hpp>
      45              : 
      46              : 
      47              : namespace ert
      48              : {
      49              : namespace diametercodec
      50              : {
      51              : namespace stack
      52              : {
      53              : 
      54           25 : void Dictionary::initialize() {
      55           25 :     formats_.clear();
      56           25 :     vendors_.clear();
      57           25 :     avps_.clear();
      58           25 :     commands_.clear();
      59           25 :     vendor_names_.clear();
      60           25 :     avp_names_.clear();
      61           25 :     command_names_.clear();
      62              : 
      63              :     // RFC6733 Diameter Formats harcoding:
      64              :     // Basic diameter types
      65           25 :     Format OctetString(this), Integer32(this), Integer64(this), Unsigned32(this), Unsigned64(this), Float32(this), Float64(this), Grouped(this);
      66           25 :     OctetString.setType(Format::Type::OctetString);
      67           25 :     Integer32.setType(Format::Type::Integer32);
      68           25 :     Integer64.setType(Format::Type::Integer64);
      69           25 :     Unsigned32.setType(Format::Type::Unsigned32);
      70           25 :     Unsigned64.setType(Format::Type::Unsigned64);
      71           25 :     Float32.setType(Format::Type::Float32);
      72           25 :     Float64.setType(Format::Type::Float64);
      73           25 :     Grouped.setType(Format::Type::Grouped);
      74              : 
      75           25 :     addFormat(OctetString);
      76           25 :     addFormat(Integer32);
      77           25 :     addFormat(Integer64);
      78           25 :     addFormat(Unsigned32);
      79           25 :     addFormat(Unsigned64);
      80           25 :     addFormat(Float32);
      81           25 :     addFormat(Float64);
      82           25 :     addFormat(Grouped);
      83              : 
      84              :     // Derived diameter types
      85           25 :     Format Address(this), Time(this), UTF8String(this), DiameterIdentity(this), DiameterURI(this), Enumerated(this), IPFilterRule(this), QoSFilterRule(this);
      86           25 :     Address.setType(Format::Type::Address);
      87           25 :     Address.setParentName(OctetString.getName());
      88           25 :     Time.setType(Format::Type::Time);
      89           25 :     Time.setParentName(OctetString.getName());
      90           25 :     UTF8String.setType(Format::Type::UTF8String);
      91           25 :     UTF8String.setParentName(OctetString.getName());
      92           25 :     DiameterIdentity.setType(Format::Type::DiameterIdentity);
      93           25 :     DiameterIdentity.setParentName(OctetString.getName());
      94           25 :     DiameterURI.setType(Format::Type::DiameterURI);
      95           25 :     DiameterURI.setParentName(OctetString.getName());
      96           25 :     Enumerated.setType(Format::Type::Enumerated);
      97           25 :     Enumerated.setParentName(Integer32.getName());
      98           25 :     IPFilterRule.setType(Format::Type::IPFilterRule);
      99           25 :     IPFilterRule.setParentName(OctetString.getName());
     100           25 :     QoSFilterRule.setType(Format::Type::QoSFilterRule);
     101           25 :     QoSFilterRule.setParentName(OctetString.getName());
     102              : 
     103           25 :     addFormat(Address);
     104           25 :     addFormat(Time);
     105           25 :     addFormat(UTF8String);
     106           25 :     addFormat(DiameterIdentity);
     107           25 :     addFormat(DiameterURI);
     108           25 :     addFormat(Enumerated);
     109           25 :     addFormat(IPFilterRule);
     110           25 :     addFormat(QoSFilterRule);
     111              : 
     112              :     // Generic AVP format:
     113           25 :     Format Any(this);
     114           25 :     Any.setType(Format::Type::Any);
     115           25 :     addFormat(Any, true /*reserved*/);
     116              : 
     117              :     // Generic AVP:
     118           25 :     Avp genericAvp(this);
     119           25 :     genericAvp.setCode(0);
     120           25 :     genericAvp.setVendorId(0/*Vendor::Code::Ietf*/);
     121           25 :     genericAvp.setName("AVP");
     122           25 :     genericAvp.setFormatName(Any.getName());
     123           25 :     genericAvp.setVBit(false);
     124           25 :     genericAvp.setMBit(false);
     125           25 :     addAvp(genericAvp);
     126           25 : }
     127              : 
     128          425 : void Dictionary::addFormat(const Format & format, bool reserved) {
     129          425 :     if(!reserved && format.isReserved()) {
     130            0 :         std::string s_ex = ert::tracing::Logger::asString("Format type '%s' is reserved for internal use", format.getName().c_str());
     131            0 :         throw std::runtime_error(s_ex);
     132            0 :     }
     133              : 
     134          425 :     const Format * found = getFormat(format.getName());
     135          425 :     if(found) {
     136              :         // Update:
     137            0 :         LOGINFORMATIONAL(
     138              :             std::string trace = "Updated format '";
     139              :             trace += format.getName();
     140              :             trace += "'";
     141              :             ert::tracing::Logger::informational(trace, ERT_FILE_LOCATION);
     142              :         );
     143              :     }
     144              : 
     145          425 :     formats_[format.getName()] = format;
     146          425 : }
     147              : 
     148          150 : void Dictionary::addVendor(const Vendor & vendor) {
     149              : 
     150          150 :     vendors_[vendor.getCode()] = vendor;
     151          150 :     vendor_names_[vendor.getName()] = getVendor(vendor.getCode());
     152          150 : }
     153              : 
     154         2700 : void Dictionary::addAvp(const Avp & avp) {
     155              : 
     156         2700 :     avps_[avp.getId()] = avp;
     157         2700 :     avp_names_[avp.getName()] = getAvp(avp.getId());
     158         2700 : }
     159              : 
     160          350 : void Dictionary::addCommand(const Command & command) {
     161              : 
     162          350 :     commands_[command.getId()] = command;
     163          350 :     command_names_[command.getName()] = getCommand(command.getId());
     164          350 : }
     165              : 
     166        72159 : const Format * Dictionary::getFormat(const std::string & formatName) const {
     167        72159 :     auto it = formats_.find(formatName);
     168              : 
     169        72159 :     if(it != formats_.end()) return &(it->second);
     170              : 
     171          425 :     return (nullptr);
     172              : }
     173              : 
     174          150 : const Vendor * Dictionary::getVendor(core::S32 vendorId) const {
     175          150 :     auto it = vendors_.find(vendorId);
     176              : 
     177          150 :     if(it != vendors_.end()) return &(it->second);
     178              : 
     179            0 :     return (nullptr);
     180              : }
     181              : 
     182            0 : const Vendor * Dictionary::getVendor(const std::string & vendorName) const {
     183            0 :     auto it = vendor_names_.find(vendorName);
     184              : 
     185            0 :     if(it != vendor_names_.end()) return (it->second);
     186              : 
     187            0 :     return (nullptr);
     188              : }
     189              : 
     190         2705 : Avp * Dictionary::getAvp(const core::AvpId & avpId) const {
     191         2705 :     auto it = avps_.find(avpId);
     192              : 
     193         2705 :     if(it != avps_.end()) return (Avp*)&(it->second);
     194              : 
     195            0 :     return (nullptr);
     196              : }
     197              : 
     198         5726 : Avp * Dictionary::getAvp(const std::string & avpName) const {
     199         5726 :     auto it = avp_names_.find(avpName);
     200              : 
     201         5726 :     if(it != avp_names_.end()) return (Avp*)(it->second);
     202              : 
     203            0 :     return (nullptr);
     204              : }
     205              : 
     206          350 : Command * Dictionary::getCommand(const core::CommandId & commandId) const {
     207          350 :     auto it = commands_.find(commandId);
     208              : 
     209          350 :     if(it != commands_.end()) return (Command*)&(it->second);
     210              : 
     211            0 :     return (nullptr);
     212              : }
     213              : 
     214            0 : Command * Dictionary::getCommand(const std::string & commandName) const {
     215            0 :     auto it = command_names_.find(commandName);
     216              : 
     217            0 :     if(it != command_names_.end()) return (Command*)(it->second);
     218              : 
     219            0 :     return (nullptr);
     220              : }
     221              : 
     222            0 : nlohmann::json Dictionary::asJson(void) const {
     223            0 :     nlohmann::json result;
     224              : 
     225            0 :     result["name"] = name_;
     226              : 
     227              :     // Formats
     228            0 :     for(auto it: formats_) {
     229            0 :         if(it.second.isReserved()) continue;
     230            0 :         if(it.second.isRFC6733()) continue; // only user-defined formats are shown
     231            0 :         result["format"].push_back(it.second.asJson());
     232            0 :     }
     233              : 
     234              :     // Vendors
     235            0 :     for(auto it: vendors_)
     236            0 :         result["vendor"].push_back(it.second.asJson());
     237              : 
     238              :     // Avps
     239            0 :     for(auto it: avps_) {
     240            0 :         if(it.second.getFormat()->isAny()) continue;  // Generic AVP not shown
     241              : 
     242            0 :         result["avp"].push_back(it.second.asJson());
     243            0 :     }
     244              : 
     245              :     // Commands
     246            0 :     for(auto it: commands_)
     247            0 :         result["command"].push_back(it.second.asJson());
     248              : 
     249            0 :     return result;
     250            0 : }
     251              : 
     252            0 : void Dictionary::extractFormats(const nlohmann::json &doc) {
     253            0 :     for(auto it: doc) {
     254            0 :         Format aux(this); // set everything below (even empty, zeroed, etc.) to avoid reset() function
     255              : 
     256              :         // Mandatory
     257            0 :         auto name_it = it.find("name");
     258            0 :         auto ptype_it = it.find("parent-type");
     259              : 
     260              :         // Assignments:
     261            0 :         aux.setName(*name_it);
     262            0 :         aux.setParentName(*ptype_it);
     263              : 
     264              :         // New entry:
     265            0 :         addFormat(aux);
     266            0 :     }
     267            0 : }
     268              : 
     269           25 : void Dictionary::extractVendors(const nlohmann::json &doc) {
     270          325 :     for(auto it: doc) {
     271          150 :         Vendor aux; // set everything below (even empty, zeroed, etc.) to avoid reset() function
     272              : 
     273              :         // Mandatory
     274          150 :         auto name_it = it.find("name");
     275          150 :         auto code_it = it.find("code");
     276              : 
     277              :         // Assignments:
     278          150 :         aux.setCode(*code_it);
     279          150 :         aux.setName(*name_it);
     280              : 
     281              :         // New entry:
     282          150 :         addVendor(aux);
     283          150 :     }
     284           25 : }
     285              : 
     286           25 : void Dictionary::extractAvps(const nlohmann::json &doc) {
     287         2700 :     for(auto it: doc) {
     288         2675 :         Avp aux(this); // set everything below (even empty, zeroed, etc.) to avoid reset() function
     289              : 
     290              :         // Mandatory
     291         2675 :         auto name_it = it.find("name");
     292         2675 :         std::string name = *name_it;
     293         2675 :         auto code_it = it.find("code");
     294         2675 :         auto vendor_name_it = it.find("vendor-name");
     295         2675 :         core::S32 vendorCode = 0; /* IETF by default */
     296         2675 :         auto single_it = it.find("single");
     297              : 
     298              :         // Optionals
     299         2675 :         auto vbit_it = it.find("v-bit");
     300         2675 :         auto mbit_it = it.find("m-bit");
     301              : 
     302              :         // Vendor ?
     303         2675 :         if (vendor_name_it != it.end()) {
     304            0 :             std::string c_name = *vendor_name_it;
     305            0 :             auto v_it = vendor_names_.find(c_name);
     306              : 
     307            0 :             if(v_it == vendor_names_.end()) {
     308            0 :                 std::string s_ex = ert::tracing::Logger::asString("Vendor '%s', referenced at '%s' avp definition, not found at xml", c_name, name.c_str());
     309            0 :                 throw std::runtime_error(s_ex);
     310            0 :             }
     311              : 
     312            0 :             aux.setVendorName(c_name);
     313            0 :             vendorCode = ((*v_it).second)->getCode();
     314            0 :         }
     315              : 
     316              :         // Assignments:
     317         2675 :         aux.setCode(*code_it);
     318         2675 :         aux.setVendorId(vendorCode);
     319         2675 :         aux.setName(*name_it);
     320         2675 :         aux.setVBit((vbit_it!=it.end()) ? bool(*vbit_it) : false);
     321         2675 :         aux.setMBit((mbit_it!=it.end()) ? bool(*mbit_it) : false);
     322              : 
     323              :         // Check vendor specific bit:
     324         2675 :         if(vendorCode && !aux.vBit()) {
     325            0 :             std::string s_ex = ert::tracing::Logger::asString("Flag rules for vendor specific bit (mustnot) at '%s' avp definicion, are incompatible with non-zeroed vendor id %d", name.c_str(), vendorCode);
     326            0 :             throw std::runtime_error(s_ex);
     327            0 :         }
     328              : 
     329         2675 :         if(!vendorCode && aux.vBit()) {
     330            0 :             std::string s_ex = ert::tracing::Logger::asString("Flag rules for vendor specific bit (must) at '%s' avp definicion, are incompatible with zeroed vendor id %d", name.c_str(), vendorCode);
     331            0 :             throw std::runtime_error(s_ex);
     332            0 :         }
     333              : 
     334         2675 :         if(single_it != it.end()) {
     335         2225 :             auto f_it = (*single_it).find("format"); // mandatory
     336         2225 :             std::string formatName = *f_it;
     337         2225 :             auto enum_it = (*single_it).find("enum");
     338         2225 :             auto label_it = (*single_it).find("label");
     339              : 
     340              :             // Assignments:
     341         2225 :             const Format *format = getFormat(formatName);
     342              : 
     343         2225 :             if(!format) {
     344            0 :                 std::string s_ex = ert::tracing::Logger::asString("Format '%s', referenced at '%s' avp definition, not found at dictionary (neither xml nor RFC6733 diameter format types)", formatName.c_str(), name.c_str());
     345            0 :                 throw std::runtime_error(s_ex);
     346            0 :             }
     347              : 
     348         2225 :             aux.setFormatName(formatName);
     349              : 
     350         2225 :             if(enum_it != (*single_it).end()) {
     351              : 
     352          575 :                 std::string s_enum = *enum_it;
     353              : 
     354          575 :                 if(!format->isEnumerated()) {
     355            0 :                     std::string s_ex = ert::tracing::Logger::asString("Enumerated literal '%s' is not allowed for '%s' avp format", s_enum.c_str(), formatName.c_str());
     356            0 :                     throw std::runtime_error(s_ex);
     357            0 :                 }
     358              : 
     359          575 :                 aux.setEnums(s_enum.c_str());
     360          575 :             }
     361              : 
     362         2225 :             if(label_it != (*single_it).end()) {
     363         4250 :                 for(auto l_it: *label_it) {
     364         3550 :                     std::string data = *(l_it.find("data"));
     365         3550 :                     std::string alias = *(l_it.find("alias"));
     366              :                     // Assignment:
     367         3550 :                     aux.addLabel(data, alias);
     368         3550 :                 }
     369              :             }
     370         2225 :         } else { // grouped
     371              :             // Assignments:
     372          900 :             aux.setFormatName(Format::Type::asText(Format::Type::Grouped));
     373              :             // Wait for avprule insertion, because we need complete avp reference pool (*)
     374              :         }
     375              : 
     376              :         // New entry:
     377         2675 :         addAvp(aux);
     378         2675 :     }
     379              : 
     380              :     // Now process grouped ones:
     381         2700 :     for(auto it: doc) {
     382         2675 :         auto name_it = it.find("name");
     383         2675 :         auto grouped_it = it.find("grouped");
     384              : 
     385         2675 :         auto a_it = avp_names_.find(*name_it);
     386         2675 :         Avp * gavp = (Avp *)((*a_it).second);
     387              : 
     388         2675 :         if(!gavp) continue;  // it could be mising (a redefinition could have removed it)
     389              : 
     390         2675 :         const Format *format = gavp->getFormat();
     391              : 
     392              :         // Avprule updating:
     393         2675 :         if(format->isGrouped()) { // double check
     394          450 :             auto avprule_it = grouped_it->find("avprule");
     395          450 :             AvpRule auxAvpRule(this); // set everything below (even empty, zeroed, etc.) to avoid reset() function
     396         2100 :             for(auto it: *avprule_it) {
     397         1650 :                 std::string name = *(it.find("name"));
     398         1650 :                 std::string type = *(it.find("type"));
     399         1650 :                 auto qual_it = it.find("qual"); // optional
     400              : 
     401         1650 :                 const Avp * avp = getAvp(name);
     402         1650 :                 if(avp == nullptr) {
     403            0 :                     std::string s_ex = ert::tracing::Logger::asString("Avp '%s', referenced at avp rule definition within grouped '%s', not found at xml", name.c_str(), std::string(*name_it).c_str());
     404            0 :                     throw std::runtime_error(s_ex);
     405            0 :                 }
     406              : 
     407         1650 :                 auxAvpRule.setAvpId(avp->getId());
     408         1650 :                 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
     409         1650 :                 auxAvpRule.setQual((qual_it != it.end()) ? *qual_it:"");
     410         1650 :                 gavp->addAvpRule(auxAvpRule);
     411         1650 :             }
     412          450 :         }
     413         2675 :     }
     414              : 
     415              :     // Check avp loops between grouped avps:
     416              : 
     417              :     // In order to avoid loops, we could force to define grouped avps which children
     418              :     //  had been previously defined at xml file. In this way, is imposible to get a loop:
     419              :     //   C = ...
     420              :     //   D = ...
     421              :     //   A = grouped of B,C,D -> error, B unknown
     422              :     //   B = grouped of A,F -> with former definition, would become a loop
     423              :     //
     424              :     // But this supposes a restriction at json configuration (specific order).
     425              :     // The other way is an internal check: a grouped AVP won't have descendants within
     426              :     //  its ascendants. Then we will check all grouped avps in this way:
     427              :     //
     428              :     // 1. Searching for another grouped avps which are parents for this avp.
     429              :     // 2. If these are children (even this avp(*)) at avp definition, then a loop is detected.
     430              :     //
     431              :     // Example 1: (1) Analyzing 'A', found parent 'B' / (2) 'B' is already children of 'A'
     432              :     //       A -> B
     433              :     //            C
     434              :     //            D
     435              :     //       ...
     436              :     //       B -> A -> loop !!
     437              :     //            F
     438              :     //
     439              :     // (*) Example 2: (1) Analyzing 'A', found parent 'A' / (2) 'A' is already children of 'A'
     440              :     //       A -> B
     441              :     //            C
     442              :     //            D
     443              :     //            A -> loop !!
     444              :     //
     445         2725 :     for(auto it = avps_.begin(); it != avps_.end(); it++) {
     446         2700 :         const Avp & avp = (*it).second;
     447              : 
     448         2700 :         if(!((avp.getFormat())->isGrouped())) continue;
     449              : 
     450        49050 :         for(auto it_p = avps_.begin(); it_p != avps_.end(); it_p++) {
     451        48600 :             const Avp & avp_p = (*it_p).second;
     452              : 
     453        48600 :             if(!((avp_p.getFormat())->isGrouped())) continue;
     454              : 
     455         8100 :             if(avp_p.isChild(avp.getId())) {
     456          300 :                 if(avp.isChild(avp_p.getId())) {
     457            0 :                     std::string s_ex;
     458              : 
     459              : 
     460            0 :                     if(it != it_p)
     461            0 :                         s_ex = ert::tracing::Logger::asString("Loop detected between grouped avps '%s' and '%s'", avp.getName().c_str(), avp_p.getName().c_str());
     462              :                     else
     463            0 :                         s_ex = ert::tracing::Logger::asString("Loop within grouped avp '%s': cannot contain itself !!", avp.getName().c_str());
     464              : 
     465            0 :                     throw std::runtime_error(s_ex);
     466            0 :                 } // parent is children of (ref): loop !
     467              :             } // parent found
     468              :         } // search parents
     469              :     } // search grouped avps (ref)
     470           25 : }
     471              : 
     472           25 : void Dictionary::extractCommands(const nlohmann::json &doc) {
     473          725 :     for(auto it: doc) {
     474          350 :         Command aux; // set everything below (even empty, zeroed, etc.) to avoid reset() function
     475              : 
     476              :         // Mandatory
     477          350 :         auto name_it = it.find("name");
     478          350 :         auto code_it = it.find("code");
     479          350 :         auto avprule_it = it.find("avprule");
     480              : 
     481              :         // Optionals
     482          350 :         auto appid_it = it.find("application-id");
     483          350 :         auto rbit_it = it.find("r-bit");
     484          350 :         auto pbit_it = it.find("p-bit");
     485              : 
     486              :         // Assignments:
     487          350 :         aux.setName(*name_it);
     488          350 :         aux.setCode(*code_it);
     489          350 :         aux.setApplicationId((appid_it!=it.end()) ? core::U32(*appid_it) : 0);
     490          350 :         aux.setRequest((rbit_it!=it.end()) ? bool(*rbit_it) : false);
     491          350 :         aux.setPBit((pbit_it!=it.end()) ? bool(*pbit_it) : false);
     492              : 
     493          350 :         AvpRule auxAvpRule(this); // set everything below (even empty, zeroed, etc.) to avoid reset() function
     494         8500 :         for(auto it: *avprule_it) {
     495         4075 :             std::string name = *(it.find("name"));
     496         4075 :             std::string type = *(it.find("type"));
     497         4075 :             auto qual_it = it.find("qual"); // optional
     498              : 
     499         4075 :             const Avp * avp = getAvp(name);
     500         4075 :             if(avp == nullptr) {
     501            0 :                 std::string s_ex = ert::tracing::Logger::asString("Avp '%s', referenced at avp rule definition within command '%s', not found at xml", name.c_str(), std::string(*name_it).c_str());
     502            0 :                 throw std::runtime_error(s_ex);
     503            0 :             }
     504              : 
     505         4075 :             auxAvpRule.setAvpId(avp->getId());
     506         4075 :             auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
     507         4075 :             auxAvpRule.setQual((qual_it != it.end()) ? *qual_it:"");
     508         4075 :             aux.addAvpRule(auxAvpRule);
     509         4075 :         }
     510              : 
     511              :         // New entry:
     512          350 :         addCommand(aux);
     513          350 :     }
     514           25 : }
     515              : 
     516           25 : void Dictionary::load(const nlohmann::json &json) {
     517              : 
     518              :     // Mandatory
     519           25 :     auto name_it = json.find("name");
     520           25 :     name_ = *name_it;
     521              : 
     522              :     // Optional
     523           25 :     auto formats_it = json.find("format");
     524           25 :     if (formats_it != json.end() && formats_it->is_array()) {
     525            0 :         extractFormats(*formats_it);
     526              :     }
     527              : 
     528           25 :     auto vendors_it = json.find("vendor");
     529           25 :     if (vendors_it != json.end() && vendors_it->is_array()) {
     530           25 :         extractVendors(*vendors_it);
     531              :     }
     532              : 
     533           25 :     auto avps_it = json.find("avp");
     534           25 :     if (avps_it != json.end() && avps_it->is_array()) {
     535           25 :         extractAvps(*avps_it);
     536              :     }
     537              : 
     538           25 :     auto commands_it = json.find("command");
     539           25 :     if (commands_it != json.end() && commands_it->is_array()) {
     540           25 :         extractCommands(*commands_it);
     541              :     }
     542           25 : }
     543              : 
     544              : }
     545              : }
     546              : }
     547              : 
        

Generated by: LCOV version 2.0-1